lib/lightning/onion/chacha20.rb in lightning-onion-0.2.9 vs lib/lightning/onion/chacha20.rb in lightning-onion-0.2.10
- old
+ new
@@ -1,98 +1,18 @@
# frozen_string_literal: true
module Lightning
module Onion
module ChaCha20
- def self.constants
- [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574].pack('N*')
- end
+ autoload :OpenSSL, 'lightning/onion/chacha20/openssl'
+ autoload :Pure, 'lightning/onion/chacha20/pure'
def self.chacha20_encrypt(key, counter, nonce, plaintext)
- encrypted_message = +''
- (plaintext.length / 64).times do |i|
- key_stream = chacha20_block(key, counter + i, nonce)
- block = plaintext[(i * 64)...(i + 1) * 64]
- encrypted_message += xor(block, key_stream)
+ if ::OpenSSL::Cipher.ciphers.include?("ChaCha20")
+ Lightning::Onion::ChaCha20::OpenSSL.chacha20_encrypt(key, counter, nonce, plaintext)
+ else
+ Lightning::Onion::ChaCha20::Pure.chacha20_encrypt(key, counter, nonce, plaintext)
end
- if plaintext.length % 64 != 0
- i = plaintext.length / 64
- key_stream = chacha20_block(key, counter + i, nonce)
- block = plaintext[(i * 64)...plaintext.length]
- block = block.ljust(64, "\x00")
- encrypted_message += xor(block, key_stream)[0...(plaintext.length % 64)]
- end
- encrypted_message
- end
-
- def self.xor(a, b)
- a = a.unpack('N*')
- b = b.unpack('N*')
- a.zip(b).map { |x, y| (x ^ y) & 0xffffffff }.pack('N*')
- end
-
- # key: 32 bytes
- # counter: integer (4 bytes)
- # nonce: 12 bytes
- def self.chacha20_block(key, counter, nonce)
- # reverse order
- key = key.unpack('V*').pack('N*')
- counter = [counter].pack('N*')
- nonce = nonce.unpack('V*').pack('N*')
- state = constants + key + counter + nonce
- working_state = state.unpack('N*')
- 10.times do
- inner_block(working_state)
- end
- plus_for_string(state, working_state)
- end
-
- def self.inner_block(x)
- # column rounds
- x[0], x[4], x[8], x[12] = quater_round(x[0], x[4], x[8], x[12])
- x[1], x[5], x[9], x[13] = quater_round(x[1], x[5], x[9], x[13])
- x[2], x[6], x[10], x[14] = quater_round(x[2], x[6], x[10], x[14])
- x[3], x[7], x[11], x[15] = quater_round(x[3], x[7], x[11], x[15])
- # diagonal rounds
- x[0], x[5], x[10], x[15] = quater_round(x[0], x[5], x[10], x[15])
- x[1], x[6], x[11], x[12] = quater_round(x[1], x[6], x[11], x[12])
- x[2], x[7], x[8], x[13] = quater_round(x[2], x[7], x[8], x[13])
- x[3], x[4], x[9], x[14] = quater_round(x[3], x[4], x[9], x[14])
- end
-
- def self.plus_for_string(a, b)
- a.unpack('N*').map.with_index do |x, i|
- plus(x, b[i])
- end.pack('V*')
- end
-
- def self.plus(x, y)
- (x + y) & 0xffffffff
- end
-
- def self.rotate(x, n)
- y = x << n
- z = x >> (32 - n)
- (y | z) & 0xffffffff
- end
-
- def self.quater_round(a, b, c, d)
- a = plus(a, b)
- d ^= a
- d = rotate(d, 16)
-
- c = plus(c, d)
- b ^= c
- b = rotate(b, 12)
-
- a = plus(a, b)
- d ^= a
- d = rotate(d, 8)
-
- c = plus(c, d)
- b ^= c
- b = rotate(b, 7)
- [a, b, c, d]
end
end
end
end