Class: CMAC
- Inherits:
-
Object
- Object
- CMAC
- Defined in:
- lib/cmac.rb,
lib/cmac/version.rb
Constant Summary collapse
- Exception =
Class.new(StandardError)
- ZeroBlock =
"\0" * 16
- ConstantBlock =
("\0" * 15) + "\x87"
- VERSION =
'0.3.0'
Instance Method Summary collapse
- #_derive_key(key) ⇒ Object
- #_encrypt_block(key, block) ⇒ Object
- #_generate_subkeys(key) ⇒ Object
- #_leftshift(input) ⇒ Object
- #_needs_padding?(message) ⇒ Boolean
- #_next_key(key) ⇒ Object
- #_pad_message(message) ⇒ Object
- #_secure_compare?(a, b) ⇒ Boolean
- #_xor(a, b) ⇒ Object
-
#initialize(key) ⇒ CMAC
constructor
A new instance of CMAC.
- #inspect ⇒ Object
- #sign(message, truncate = 16) ⇒ Object (also: #encrypt)
- #valid_message?(tag, message) ⇒ Boolean
Constructor Details
#initialize(key) ⇒ CMAC
Returns a new instance of CMAC.
10 11 12 13 |
# File 'lib/cmac.rb', line 10 def initialize(key) @key = _derive_key(key.b) @key1, @key2 = _generate_subkeys(@key) end |
Instance Method Details
#_derive_key(key) ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/cmac.rb', line 54 def _derive_key(key) if key.length == 16 key else cmac = CMAC.new(ZeroBlock) cmac.encrypt(key) end end |
#_encrypt_block(key, block) ⇒ Object
63 64 65 66 67 68 69 |
# File 'lib/cmac.rb', line 63 def _encrypt_block(key, block) cipher = OpenSSL::Cipher.new('AES-128-ECB') cipher.encrypt cipher.padding = 0 cipher.key = key cipher.update(block) + cipher.final end |
#_generate_subkeys(key) ⇒ Object
71 72 73 74 75 76 |
# File 'lib/cmac.rb', line 71 def _generate_subkeys(key) key0 = _encrypt_block(key, ZeroBlock) key1 = _next_key(key0) key2 = _next_key(key1) [key1, key2] end |
#_leftshift(input) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/cmac.rb', line 90 def _leftshift(input) overflow = 0 words = input.unpack('N4').reverse words = words.map do |word| new_word = (word << 1) & 0xFFFFFFFF new_word |= overflow overflow = (word & 0x80000000) >= 0x80000000 ? 1 : 0 new_word end words.reverse.pack('N4') end |
#_needs_padding?(message) ⇒ Boolean
78 79 80 |
# File 'lib/cmac.rb', line 78 def _needs_padding?() .length == 0 || .length % 16 != 0 end |
#_next_key(key) ⇒ Object
82 83 84 85 86 87 88 |
# File 'lib/cmac.rb', line 82 def _next_key(key) if key[0].ord < 0x80 _leftshift(key) else _xor(_leftshift(key), ConstantBlock) end end |
#_pad_message(message) ⇒ Object
102 103 104 105 106 |
# File 'lib/cmac.rb', line 102 def () padded_length = .length + 16 - (.length % 16) = + "\x80".b .ljust(padded_length, "\0") end |
#_secure_compare?(a, b) ⇒ Boolean
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/cmac.rb', line 108 def _secure_compare?(a, b) return false unless a.bytesize == b.bytesize bytes = a.unpack("C#{a.bytesize}") result = 0 b.each_byte do |byte| result |= byte ^ bytes.shift end result == 0 end |
#_xor(a, b) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/cmac.rb', line 120 def _xor(a, b) a = a.b b = b.b output = '' length = [a.length, b.length].min length.times do |i| output << (a[i].ord ^ b[i].ord).chr end output end |
#inspect ⇒ Object
15 16 17 |
# File 'lib/cmac.rb', line 15 def inspect "#<CMAC:0x#{object_id.to_s(16)}>" end |
#sign(message, truncate = 16) ⇒ Object Also known as: encrypt
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 |
# File 'lib/cmac.rb', line 19 def sign(, truncate = 16) raise CMAC::Exception.new('Tag cannot be greater than maximum (16 bytes)') if truncate > 16 raise CMAC::Exception.new('Tag cannot be less than minimum (8 bytes)') if truncate < 8 = .b if _needs_padding?() = () final_block = @key2 else final_block = @key1 end last_ciphertext = ZeroBlock count = .length / 16 range = Range.new(0, count - 1) blocks = range.map { |i| .slice(16 * i, 16) } blocks.each_with_index do |block, i| if i == range.last block = _xor(final_block, block) end block = _xor(block, last_ciphertext) last_ciphertext = _encrypt_block(@key, block) end last_ciphertext.slice(0, truncate) end |
#valid_message?(tag, message) ⇒ Boolean
49 50 51 52 |
# File 'lib/cmac.rb', line 49 def (tag, ) other_tag = sign() _secure_compare?(tag, other_tag) end |