Class: Bitcoin::BIP324::Cipher
- Inherits:
-
Object
- Object
- Bitcoin::BIP324::Cipher
- Includes:
- Util
- Defined in:
- lib/bitcoin/bip324/cipher.rb
Overview
The BIP324 packet cipher, encapsulating its key derivation, stream cipher, and AEAD.
Constant Summary collapse
- HEADER =
[1 << 7].pack('C')
- HEADER_LEN =
1
- LENGTH_LEN =
3
- EXPANSION =
LENGTH_LEN + HEADER_LEN + 16
Instance Attribute Summary collapse
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#our_pubkey ⇒ Object
readonly
Returns the value of attribute our_pubkey.
-
#recv_garbage_terminator ⇒ Object
Returns the value of attribute recv_garbage_terminator.
-
#recv_l_cipher ⇒ Object
Returns the value of attribute recv_l_cipher.
-
#recv_p_cipher ⇒ Object
Returns the value of attribute recv_p_cipher.
-
#send_garbage_terminator ⇒ Object
Returns the value of attribute send_garbage_terminator.
-
#send_l_cipher ⇒ Object
Returns the value of attribute send_l_cipher.
-
#send_p_cipher ⇒ Object
Returns the value of attribute send_p_cipher.
-
#session_id ⇒ Object
Returns the value of attribute session_id.
Instance Method Summary collapse
-
#decrypt(input, aad: '', ignore: false) ⇒ String
Decrypt a packet.
-
#encrypt(contents, aad: '', ignore: false) ⇒ Object
Encrypt a packet.
-
#initialize(key, our_pubkey = nil) ⇒ Cipher
constructor
Constructor.
-
#setup(their_pubkey, initiator, self_decrypt = false) ⇒ Object
Setup when the other side’s public key is received.
Methods included from Util
#byte_to_bit, #calc_checksum, #decode_base58_address, #double_sha256, #encode_base58_address, #hash160, #hkdf_sha256, #hmac_sha256, #pack_boolean, #pack_var_int, #pack_var_string, #padding_zero, #sha256, #tagged_hash, #unpack_boolean, #unpack_var_int, #unpack_var_int_from_io, #unpack_var_string, #valid_address?
Constructor Details
#initialize(key, our_pubkey = nil) ⇒ Cipher
Constructor
27 28 29 30 31 32 |
# File 'lib/bitcoin/bip324/cipher.rb', line 27 def initialize(key, our_pubkey = nil) raise ArgumentError, "key must be Bitcoin::Key" unless key.is_a?(Bitcoin::Key) raise ArgumentError, "our_pubkey must be Bitcoin::BIP324::EllSwiftPubkey" if our_pubkey && !our_pubkey.is_a?(Bitcoin::BIP324::EllSwiftPubkey) @our_pubkey = our_pubkey ? our_pubkey : key.create_ell_pubkey @key = key end |
Instance Attribute Details
#key ⇒ Object (readonly)
Returns the value of attribute key.
12 13 14 |
# File 'lib/bitcoin/bip324/cipher.rb', line 12 def key @key end |
#our_pubkey ⇒ Object (readonly)
Returns the value of attribute our_pubkey.
13 14 15 |
# File 'lib/bitcoin/bip324/cipher.rb', line 13 def our_pubkey @our_pubkey end |
#recv_garbage_terminator ⇒ Object
Returns the value of attribute recv_garbage_terminator.
17 18 19 |
# File 'lib/bitcoin/bip324/cipher.rb', line 17 def recv_garbage_terminator @recv_garbage_terminator end |
#recv_l_cipher ⇒ Object
Returns the value of attribute recv_l_cipher.
20 21 22 |
# File 'lib/bitcoin/bip324/cipher.rb', line 20 def recv_l_cipher @recv_l_cipher end |
#recv_p_cipher ⇒ Object
Returns the value of attribute recv_p_cipher.
21 22 23 |
# File 'lib/bitcoin/bip324/cipher.rb', line 21 def recv_p_cipher @recv_p_cipher end |
#send_garbage_terminator ⇒ Object
Returns the value of attribute send_garbage_terminator.
16 17 18 |
# File 'lib/bitcoin/bip324/cipher.rb', line 16 def send_garbage_terminator @send_garbage_terminator end |
#send_l_cipher ⇒ Object
Returns the value of attribute send_l_cipher.
18 19 20 |
# File 'lib/bitcoin/bip324/cipher.rb', line 18 def send_l_cipher @send_l_cipher end |
#send_p_cipher ⇒ Object
Returns the value of attribute send_p_cipher.
19 20 21 |
# File 'lib/bitcoin/bip324/cipher.rb', line 19 def send_p_cipher @send_p_cipher end |
#session_id ⇒ Object
Returns the value of attribute session_id.
15 16 17 |
# File 'lib/bitcoin/bip324/cipher.rb', line 15 def session_id @session_id end |
Instance Method Details
#decrypt(input, aad: '', ignore: false) ⇒ String
Decrypt a packet. Only after setup.
93 94 95 96 97 |
# File 'lib/bitcoin/bip324/cipher.rb', line 93 def decrypt(input, aad: '', ignore: false) len = decrypt_length(input[0...Bitcoin::BIP324::Cipher::LENGTH_LEN]) raise Bitcoin::BIP324::InvalidPaketLength unless input.bytesize == len + EXPANSION recv_p_cipher.decrypt(aad, input[Bitcoin::BIP324::Cipher::LENGTH_LEN..-1]) end |
#encrypt(contents, aad: '', ignore: false) ⇒ Object
Encrypt a packet. Only after setup.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/bitcoin/bip324/cipher.rb', line 70 def encrypt(contents, aad: '', ignore: false) raise Bitcoin::BIP324::TooLargeContent unless contents.bytesize <= (2**24 - 1) # encrypt length len = Array.new(3) len[0] = contents.bytesize & 0xff len[1] = (contents.bytesize >> 8) & 0xff len[2] = (contents.bytesize >> 16) & 0xff enc_plaintext_len = send_l_cipher.encrypt(len.pack('C*')) # encrypt contents header = ignore ? HEADER : "00".htb plaintext = header + contents aead_ciphertext = send_p_cipher.encrypt(aad, plaintext) enc_plaintext_len + aead_ciphertext end |
#setup(their_pubkey, initiator, self_decrypt = false) ⇒ Object
Setup when the other side’s public key is received. and decryption can be tested without knowing the other side’s private key.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/bitcoin/bip324/cipher.rb', line 39 def setup(their_pubkey, initiator, self_decrypt = false) salt = 'bitcoin_v2_shared_secret' + Bitcoin.chain_params.magic_head.htb ecdh_secret = BIP324.v2_ecdh(key.priv_key, their_pubkey, our_pubkey, initiator).htb terminator = hkdf_sha256(ecdh_secret, salt, 'garbage_terminators') side = initiator != self_decrypt if side self.send_l_cipher = FSChaCha20.new(hkdf_sha256(ecdh_secret, salt, 'initiator_L')) self.send_p_cipher = FSChaCha20Poly1305.new(hkdf_sha256(ecdh_secret, salt, 'initiator_P')) self.recv_l_cipher = FSChaCha20.new(hkdf_sha256(ecdh_secret, salt, 'responder_L')) self.recv_p_cipher = FSChaCha20Poly1305.new(hkdf_sha256(ecdh_secret, salt, 'responder_P')) else self.recv_l_cipher = FSChaCha20.new(hkdf_sha256(ecdh_secret, salt, 'initiator_L')) self.recv_p_cipher = FSChaCha20Poly1305.new(hkdf_sha256(ecdh_secret, salt, 'initiator_P')) self.send_l_cipher = FSChaCha20.new(hkdf_sha256(ecdh_secret, salt, 'responder_L')) self.send_p_cipher = FSChaCha20Poly1305.new(hkdf_sha256(ecdh_secret, salt, 'responder_P')) end if initiator self.send_garbage_terminator = terminator[0...16].bth self.recv_garbage_terminator = terminator[16..-1].bth else self.recv_garbage_terminator = terminator[0...16].bth self.send_garbage_terminator = terminator[16..-1].bth end self.session_id = hkdf_sha256(ecdh_secret, salt, 'session_id').bth end |