Class: Ciri::DevP2P::RLPX::FrameIO
- Inherits:
-
Object
- Object
- Ciri::DevP2P::RLPX::FrameIO
- Defined in:
- lib/ciri/devp2p/rlpx/frame_io.rb
Defined Under Namespace
Classes: Error, InvalidError, OverflowError
Constant Summary collapse
- MAX_MESSAGE_SIZE =
max message size, took 3 byte to store message size, equal to uint24 max size
(1 << 24) - 1
Instance Attribute Summary collapse
-
#snappy ⇒ Object
Returns the value of attribute snappy.
Instance Method Summary collapse
-
#initialize(io, secrets) ⇒ FrameIO
constructor
A new instance of FrameIO.
- #read_msg ⇒ Object
- #send_data(code, data) ⇒ Object
- #write_msg(msg) ⇒ Object
Constructor Details
#initialize(io, secrets) ⇒ FrameIO
Returns a new instance of FrameIO.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/ciri/devp2p/rlpx/frame_io.rb', line 45 def initialize(io, secrets) @io = io @secrets = secrets @snappy = false # snappy compress mac_aes_version = secrets.mac.size * 8 @mac = OpenSSL::Cipher.new("AES#{mac_aes_version}") @mac.encrypt @mac.key = secrets.mac # init encrypt/decrypt aes_version = secrets.aes.size * 8 @encrypt = OpenSSL::Cipher::AES.new(aes_version, :CTR) @decrypt = OpenSSL::Cipher::AES.new(aes_version, :CTR) zero_iv = "\x00".b * @encrypt.iv_len @encrypt.iv = zero_iv @encrypt.key = secrets.aes @decrypt.iv = zero_iv @decrypt.key = secrets.aes end |
Instance Attribute Details
#snappy ⇒ Object
Returns the value of attribute snappy.
43 44 45 |
# File 'lib/ciri/devp2p/rlpx/frame_io.rb', line 43 def snappy @snappy end |
Instance Method Details
#read_msg ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/ciri/devp2p/rlpx/frame_io.rb', line 111 def read_msg # verify header mac head_buf = read(32) verify_mac = update_mac(@secrets.ingress_mac, head_buf[0...16]) unless Ciri::Utils.secret_compare(verify_mac, head_buf[16...32]) raise InvalidError.new('bad header mac') end # decrypt header head_buf[0...16] = @decrypt.update(head_buf[0...16]) + @decrypt.final # read frame frame_size = read_frame_size head_buf # frame size should padded to n*16 bytes need_padding = frame_size % 16 padded_frame_size = need_padding > 0 ? frame_size + (16 - need_padding) : frame_size frame_buf = read(padded_frame_size) # verify frame mac @secrets.ingress_mac.update(frame_buf) frame_digest = @secrets.ingress_mac.digest verify_mac = update_mac(@secrets.ingress_mac, frame_digest) # clear head_buf 16...32 bytes(header mac), since we will not need it frame_mac = head_buf[16...32] = read(16) unless Ciri::Utils.secret_compare(verify_mac, frame_mac) raise InvalidError.new('bad frame mac') end # decrypt frame frame_content = @decrypt.update(frame_buf) + @decrypt.final frame_content = frame_content[0...frame_size] msg_code = RLP.decode_with_type frame_content[0], Integer msg = Message.new(code: msg_code, size: frame_content.size - 1, payload: frame_content[1..-1]) # snappy decompress if enable if snappy msg.payload = Snappy.inflate(msg.payload) msg.size = msg.payload.size end msg end |
#send_data(code, data) ⇒ Object
66 67 68 69 |
# File 'lib/ciri/devp2p/rlpx/frame_io.rb', line 66 def send_data(code, data) msg = Message.new(code: code, size: data.size, payload: data) write_msg(msg) end |
#write_msg(msg) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/ciri/devp2p/rlpx/frame_io.rb', line 71 def write_msg(msg) pkg_type = RLP.encode_with_type msg.code, Integer, zero: "\x00" # use snappy compress if enable if snappy if msg.size > MAX_MESSAGE_SIZE raise OverflowError.new("Message size is overflow, msg size: #{msg.size}") end msg.payload = Snappy.deflate(msg.payload) msg.size = msg.payload.size end # write header head_buf = "\x00".b * 32 frame_size = pkg_type.size + msg.size if frame_size > MAX_MESSAGE_SIZE raise OverflowError.new("Message size is overflow, frame size: #{frame_size}") end write_frame_size(head_buf, frame_size) # Can't find related RFC or RLPX Spec, below code is copy from geth # write zero header, but I can't find spec or explanations of 'zero header' head_buf[3..5] = [0xC2, 0x80, 0x80].pack('c*') # encrypt first half head_buf[0...16] = @encrypt.update(head_buf[0...16]) + @encrypt.final # write header mac head_buf[16...32] = update_mac(@secrets.egress_mac, head_buf[0...16]) @io.write head_buf # write encrypt frame write_frame(pkg_type) write_frame(msg.payload) # pad to n*16 bytes if (need_padding = frame_size % 16) > 0 write_frame("\x00".b * (16 - need_padding)) end finish_write_frame end |