Module: Rex::Crypto::KeyWrap::NIST_SP_800_38f
- Defined in:
- lib/rex/crypto/key_wrap/nist_sp_800_38f.rb
Class Method Summary collapse
-
.aes_unwrap(kek, key_data, authenticate: true) ⇒ String?
Performs AES key unwrapping from NIST SP 800-38F.
Class Method Details
.aes_unwrap(kek, key_data, authenticate: true) ⇒ String?
Performs AES key unwrapping from NIST SP 800-38F.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/rex/crypto/key_wrap/nist_sp_800_38f.rb', line 16 def self.aes_unwrap(kek, key_data, authenticate: true) # padded mode as described in Section 6.3 is not supported at this time raise Rex::ArgumentError.new('kek must be 16, 24 or 32-bytes long') unless [16, 24, 32].include?(kek.length) raise Rex::ArgumentError.new('key_data length must be a multiple of 8') unless key_data.length % 8 == 0 icv1 = ("\xa6".b * 8) r = key_data.bytes.each_slice(8).map { |c| c.pack('C*') } a = r.shift ciph = -> (data) do # per-section 5.1, AES is the only suitable block cipher cipher = OpenSSL::Cipher::AES.new(kek.length * 8, :ECB).decrypt cipher.key = kek cipher.padding = 0 cipher.update(data) end n = r.length 5.downto(0) do |j| (n - 1).downto(0) do |i| atr = [a.unpack1('Q>') ^ ((n * j) + i + 1)].pack('Q>') + r[i] b = ciph.call(atr) a = b[...8] r[i] = b[-8...] end end # setting authenticate to true effectively switches the operation from Section 6.2 algorithm #2 to algorithm #4 if authenticate && a != icv1 raise Rex::RuntimeError.new('ICV1 integrity check failed in KW-AD(C)') end r.join('') end |