summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoro <o@immerda.ch>2011-06-25 20:24:48 +0200
committero <o@immerda.ch>2011-06-25 20:24:48 +0200
commitf8eb36b0eb9c7c3848109c59d992f32f76733d33 (patch)
treeb8f073c88d82a129977c95fcb4b8007424ba7f7e
parentc2eae6fa1ee87599307321b9d432e4148f41c228 (diff)
setup some parsing infrastructure.
the plan is to have classes fore every packet type and (in a separate module) the same classes again, but extended by a parsing module such that each packet can parse itself. detect first packet headers and parse its size. can be used e.g. with: FPG::Parse::Parser.parse( File.open( "spec/fixtures/test.bin.pub" ) ) will create a Signature Packet with size 13
-rw-r--r--lib/fpg/io/radix64.rb180
-rw-r--r--lib/fpg/packets/new_packet.rb7
-rw-r--r--lib/fpg/packets/signature.rb6
-rw-r--r--lib/fpg/parse/_packet_headers.rb51
-rw-r--r--lib/fpg/parse/new_packet.rb21
-rw-r--r--lib/fpg/parse/new_packet_header.rb23
-rw-r--r--lib/fpg/parse/parser.rb10
-rw-r--r--lib/fpg/parse/signature.rb10
-rw-r--r--spec/radix64_spec.rb3
9 files changed, 221 insertions, 90 deletions
diff --git a/lib/fpg/io/radix64.rb b/lib/fpg/io/radix64.rb
index 49102a0..4ecdaf3 100644
--- a/lib/fpg/io/radix64.rb
+++ b/lib/fpg/io/radix64.rb
@@ -1,101 +1,103 @@
module FPG
- class Radix64
- def char_table
- @char_table ||= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".each_byte.collect.to_a
- end
- def pad
- pad_s.unpack("C1!").first
- end
- def pad_s
- "="
- end
- def char2six_table
- @char2six_table ||= Hash[char_table.zip((0..63).to_a)]
- end
- def char2six(char)
- char2six_table[char]
- end
- def six2char(six)
- char_table[six]
- end
- def quad2bytes(quad)
- q = (quad.unpack("C4!").collect { |v| char2six(v) }).to_a
- [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)+(q[2]>>2), ((q[2]<<6)%256)+q[3] ]
- end
- def padded_quad2bytes(quad)
- if quad[2] == pad_s then
- q = quad.unpack("C2!").collect { |v| char2six(v) }
- [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)>>4 ]
- else
- q = quad.unpack("C3!").collect { |v| char2six(v) }
- [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)+(q[2]>>2), ((q[2]<<6)%256) ]
- end
- end
- def bytes2quad(bytes)
- [ six2char(bytes[0]>>2), six2char(((bytes[0]<<4)%64)+(bytes[1]>>4)),
- six2char(((bytes[1]<<2)%64)+(bytes[2]>>6)), six2char(bytes[2]%64) ].pack("C4!")
- end
- def bytes2padded_quad(bytes)
- if bytes.length == 1
- [six2char(bytes[0]>>2), six2char((bytes[0]<<4)%64), pad, pad].pack("C4!")
- elsif bytes.length == 2
- [ six2char(bytes[0]>>2), six2char(((bytes[0]<<4)%64)+(bytes[1]>>4)),
- six2char((bytes[1]<<2)%64), pad].pack("C4!")
- end
- end
- def de_armor( stream )
- stream.each do |line|
- line.chop!
- return if line.length == 0
- 0.step(line.length-1, 4) do |i|
- quad = line[i..i+3]
- if quad[3] == pad_s
- bytes = padded_quad2bytes(quad)
- if bytes.length == 2 and bytes[1] != 0
- yield bytes[0]
- yield bytes[1]
- elsif bytes[0] != 0
- yield bytes[0]
+ module Io
+ class Radix64
+ def char_table
+ @char_table ||= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".each_byte.collect.to_a
+ end
+ def pad
+ pad_s.unpack("C1!").first
+ end
+ def pad_s
+ "="
+ end
+ def char2six_table
+ @char2six_table ||= Hash[char_table.zip((0..63).to_a)]
+ end
+ def char2six(char)
+ char2six_table[char]
+ end
+ def six2char(six)
+ char_table[six]
+ end
+ def quad2bytes(quad)
+ q = (quad.unpack("C4!").collect { |v| char2six(v) }).to_a
+ [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)+(q[2]>>2), ((q[2]<<6)%256)+q[3] ]
+ end
+ def padded_quad2bytes(quad)
+ if quad[2] == pad_s then
+ q = quad.unpack("C2!").collect { |v| char2six(v) }
+ [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)>>4 ]
+ else
+ q = quad.unpack("C3!").collect { |v| char2six(v) }
+ [ (q[0]<<2)+(q[1]>>4), ((q[1]<<4)%256)+(q[2]>>2), ((q[2]<<6)%256) ]
+ end
+ end
+ def bytes2quad(bytes)
+ [ six2char(bytes[0]>>2), six2char(((bytes[0]<<4)%64)+(bytes[1]>>4)),
+ six2char(((bytes[1]<<2)%64)+(bytes[2]>>6)), six2char(bytes[2]%64) ].pack("C4!")
+ end
+ def bytes2padded_quad(bytes)
+ if bytes.length == 1
+ [six2char(bytes[0]>>2), six2char((bytes[0]<<4)%64), pad, pad].pack("C4!")
+ elsif bytes.length == 2
+ [ six2char(bytes[0]>>2), six2char(((bytes[0]<<4)%64)+(bytes[1]>>4)),
+ six2char((bytes[1]<<2)%64), pad].pack("C4!")
+ end
+ end
+ def de_armor( stream )
+ stream.each do |line|
+ line.chop!
+ return if line.length == 0
+ 0.step(line.length-1, 4) do |i|
+ quad = line[i..i+3]
+ if quad[3] == pad_s
+ bytes = padded_quad2bytes(quad)
+ if bytes.length == 2 and bytes[1] != 0
+ yield bytes[0]
+ yield bytes[1]
+ elsif bytes[0] != 0
+ yield bytes[0]
+ end
+ return
end
- return
+ bytes = quad2bytes(quad)
+ yield bytes[0]
+ yield bytes[1]
+ yield bytes[2]
end
- bytes = quad2bytes(quad)
- yield bytes[0]
- yield bytes[1]
- yield bytes[2]
end
end
- end
- def armor( stream )
- line_buffer = ""
- line_length = 0
- buffer = [0,0,0]
- buffer_size = 0
- stream.each_byte do |byte|
- if buffer_size == 3 then
- line_buffer << bytes2quad(buffer)
- line_length += 4
- buffer_size = 0
+ def armor( stream )
+ line_buffer = ""
+ line_length = 0
+ buffer = [0,0,0]
+ buffer_size = 0
+ stream.each_byte do |byte|
+ if buffer_size == 3 then
+ line_buffer << bytes2quad(buffer)
+ line_length += 4
+ buffer_size = 0
+ end
+ if line_length > 63 then
+ yield line_buffer
+ line_length = 0
+ line_buffer = ""
+ end
+ buffer[buffer_size] = byte
+ buffer_size += 1
end
- if line_length > 63 then
- yield line_buffer
- line_length = 0
- line_buffer = ""
+ if buffer_size == 1
+ line_buffer << bytes2padded_quad([buffer[0]])
+ elsif buffer_size == 2
+ line_buffer << bytes2padded_quad([buffer[0],buffer[1]])
end
- buffer[buffer_size] = byte
- buffer_size += 1
+ yield line_buffer
end
- if buffer_size == 1
- line_buffer << bytes2padded_quad([buffer[0]])
- elsif buffer_size == 2
- line_buffer << bytes2padded_quad([buffer[0],buffer[1]])
+ def armor_public_key( stream )
+ yield Versioning.public_key_header
+ armor( stream )
+ yield Versioning.public_key_footer
end
- yield line_buffer
- end
- def armor_public_key( stream )
- yield Versioning.public_key_header
- armor( stream )
- yield Versioning.public_key_footer
end
end
end
diff --git a/lib/fpg/packets/new_packet.rb b/lib/fpg/packets/new_packet.rb
new file mode 100644
index 0000000..417c737
--- /dev/null
+++ b/lib/fpg/packets/new_packet.rb
@@ -0,0 +1,7 @@
+module FPG
+ module Packets
+ class NewPacket
+ attr_accessor :byte_size
+ end
+ end
+end
diff --git a/lib/fpg/packets/signature.rb b/lib/fpg/packets/signature.rb
new file mode 100644
index 0000000..f8f4aef
--- /dev/null
+++ b/lib/fpg/packets/signature.rb
@@ -0,0 +1,6 @@
+module FPG
+ module Packets
+ class Signature < NewPacket
+ end
+ end
+end
diff --git a/lib/fpg/parse/_packet_headers.rb b/lib/fpg/parse/_packet_headers.rb
new file mode 100644
index 0000000..a016a04
--- /dev/null
+++ b/lib/fpg/parse/_packet_headers.rb
@@ -0,0 +1,51 @@
+module FPG
+ module Parse
+ module PacketHeaders
+ def packet_for( byte )
+ case byte
+ when 0
+ raise Error, "a packet tag must not be 0"
+ when 1
+ PublicKeyEncryptedSessionKey.new
+ when 2
+ Signature.new
+ when 3
+ SymmetricKeyEncryptedSession.new
+ when 4
+ OnePassSignature.new
+ when 5
+ SecretKey.new
+ when 6
+ PublicKey.new
+ when 7
+ SecretSubkey.new
+ when 8
+ CompressedData.new
+ when 9
+ SymmetricallyEncryptedData.new
+ when 10
+ Marker.new
+ when 11
+ Literal.new
+ when 12
+ Trust.new
+ when 13
+ UserId.new
+ when 14
+ PublicSubkey.new
+ when 17
+ UserAttribute.new
+ when 18
+ SymmetricEncryptedAndIntegrityProtectedData.new
+ when 19
+ MudificationDetectionCode.new
+ when 60..63
+ raise Error, 'Private or Experimental Header detected'
+ else
+ nil
+ end
+ end
+ end
+ end
+end
+
diff --git a/lib/fpg/parse/new_packet.rb b/lib/fpg/parse/new_packet.rb
new file mode 100644
index 0000000..f4e7658
--- /dev/null
+++ b/lib/fpg/parse/new_packet.rb
@@ -0,0 +1,21 @@
+module FPG
+ module Parse
+ module NewPacketParser
+ def parse( stream )
+ size= packet_size( stream )
+ puts "i'm size "+size.to_s
+ stream.seek( size, IO::SEEK_CUR )
+ end
+ def packet_size( str )
+ tag = str.getbyte
+ return tag if tag < 192
+ return ((tag-192)<<8) + str.getbyte + 192 if tag < 224
+ return (str.getbyte<<24) | (str.getbyte<<16) | (str.getbyte<<8) | str.getbyte if tag == 255
+ raise Error, "Partial Body lengths are not supported"
+ end
+ end
+ class NewPacket < Packets::NewPacket
+ include NewPacketParser
+ end
+ end
+end
diff --git a/lib/fpg/parse/new_packet_header.rb b/lib/fpg/parse/new_packet_header.rb
new file mode 100644
index 0000000..a65a82e
--- /dev/null
+++ b/lib/fpg/parse/new_packet_header.rb
@@ -0,0 +1,23 @@
+module FPG
+ module Parse
+ class NewPacketHeader
+ include PacketHeaders
+ def parse( stream )
+ stream.each_byte do |byte|
+ current_packet = packet_for( byte )
+ unless current_packet.nil? then
+ puts current_packet.inspect
+ return current_packet.parse( stream )
+ end
+ end
+ end
+ def packet_size( str )
+ tag = str.getbyte
+ return tag if tag < 192
+ return ((tag-192)<<8) + str.getbyte + 192 if tag < 224
+ return (str.getbyte<<24) | (str.getbyte<<16) | (str.getbyte<<8) | str.getbyte if tag == 255
+ raise Error, "Partial Body lengths are not supported"
+ end
+ end
+end
+end
diff --git a/lib/fpg/parse/parser.rb b/lib/fpg/parse/parser.rb
new file mode 100644
index 0000000..3d0cd26
--- /dev/null
+++ b/lib/fpg/parse/parser.rb
@@ -0,0 +1,10 @@
+module FPG
+ module Parse
+ class Parser
+ def self.parse( stream )
+ #TODO: parse until stream at end
+ NewPacketHeader.new.parse( stream )
+ end
+ end
+ end
+end
diff --git a/lib/fpg/parse/signature.rb b/lib/fpg/parse/signature.rb
new file mode 100644
index 0000000..41bee87
--- /dev/null
+++ b/lib/fpg/parse/signature.rb
@@ -0,0 +1,10 @@
+module FPG
+ module Parse
+ module SignatureParser
+ include NewPacketParser
+ end
+ class Signature < Packets::Signature
+ include SignatureParser
+ end
+ end
+end
diff --git a/spec/radix64_spec.rb b/spec/radix64_spec.rb
index 73262d1..81c9bb6 100644
--- a/spec/radix64_spec.rb
+++ b/spec/radix64_spec.rb
@@ -1,8 +1,9 @@
-
require File.join(File.dirname(__FILE__), %w[spec_helper])
require 'stringio'
+include FPG::Io
+
describe Radix64 do
before(:each) do
@radix = Radix64.new