Class: Memorandom::Plugins::AES
- Inherits:
-
Memorandom::PluginTemplate
- Object
- Memorandom::PluginTemplate
- Memorandom::Plugins::AES
- Defined in:
- lib/memorandom/plugins/aes.rb
Constant Summary collapse
- AES_KEYBLOCK_MIN =
This code is a ruby implementation of AESKeyFind © 2008-07-18 Nadia Heninger and Ariel Feldman It is approximately 360 times slower than the C implementation :(
176
- AES_XOR_LIMIT =
10
- AES_SBOX =
[ # 0 1 2 3 4 5 6 7 8 9 A B C D E F 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, #0 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, #1 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, #2 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, #3 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, #4 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, #5 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, #6 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, #7 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, #8 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, #9 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, #A 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, #B 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, #C 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, #D 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, #E 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 #F ]
- AES_RCON =
[ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb ]
- BYTE_VALUES =
Array.new([0]*256)
- ENTROPIC_MIN =
8
- M1 =
0x55555555
- M2 =
0x33333333
- M4 =
0x0f0f0f0f
- @@description =
"This plugin looks for AES encryption keys (128/256)"
- @@confidence =
0.50
Instance Attribute Summary
Attributes inherited from Memorandom::PluginTemplate
Instance Method Summary collapse
-
#aes_bit(vector, n) ⇒ Object
Return bit n of vector.
-
#aes_get_byte(vector, n) ⇒ Object
Return byte n of vector.
-
#aes_key_core(k, i) ⇒ Object
Perform the AES key core operation on a word.
-
#aes_popcount(x) ⇒ Object
Return the number of bits in x that are 1.
-
#aes_sbox_bytes(k) ⇒ Object
Run each byte of a word through the sbox separately for word 4 of 256-bit AES.
-
#aes_set_byte(vector, n, val) ⇒ Object
Set byte n of vector to val.
-
#entropic(buff, window, limit) ⇒ Object
Identifies byte windows that are “entropic” (< limit repeats of any byte) Algorithm adapted from aeskeyfind.c.
-
#scan(buffer, source_offset) ⇒ Object
Scan takes a buffer and an offset of where this buffer starts in the source.
Methods inherited from Memorandom::PluginTemplate
#confidence, confidence, #description, description, #initialize, #report_hit, #reset
Constructor Details
This class inherits a constructor from Memorandom::PluginTemplate
Instance Method Details
#aes_bit(vector, n) ⇒ Object
Return bit n of vector.
81 82 83 |
# File 'lib/memorandom/plugins/aes.rb', line 81 def aes_bit(vector, n) (vector >> n) & 1 end |
#aes_get_byte(vector, n) ⇒ Object
Return byte n of vector.
91 92 93 |
# File 'lib/memorandom/plugins/aes.rb', line 91 def aes_get_byte(vector, n) (vector >> (8*n)) & 0xff end |
#aes_key_core(k, i) ⇒ Object
Perform the AES key core operation on a word. (Assumes the standard byte order.)
63 64 65 66 67 68 69 |
# File 'lib/memorandom/plugins/aes.rb', line 63 def aes_key_core(k, i) t = 0 0.upto(3) do |j| t = aes_set_byte(t, (j-1) % 4, AES_SBOX[aes_get_byte(k, j)]) end aes_set_byte(t, 0, aes_get_byte(t,0) ^ AES_RCON[i]) end |
#aes_popcount(x) ⇒ Object
Return the number of bits in x that are 1.
96 97 98 99 100 101 102 |
# File 'lib/memorandom/plugins/aes.rb', line 96 def aes_popcount(x) x -= (x >> 1) & M1 x = (x & M2) + ((x >> 2) & M2) x = (x + (x >> 4)) & M4 x += x >> 8 (x + (x >> 16)) & 0x3f end |
#aes_sbox_bytes(k) ⇒ Object
Run each byte of a word through the sbox separately for word 4 of 256-bit AES.
72 73 74 75 76 77 78 |
# File 'lib/memorandom/plugins/aes.rb', line 72 def aes_sbox_bytes(k) r = 0 0.upto(3) do |j| r = aes_set_byte(r, j, AES_SBOX[aes_get_byte(k,j)]) end r end |
#aes_set_byte(vector, n, val) ⇒ Object
Set byte n of vector to val.
86 87 88 |
# File 'lib/memorandom/plugins/aes.rb', line 86 def aes_set_byte(vector, n, val) (vector & ~(0xff << (8*n))) | (val << (8*n)) end |
#entropic(buff, window, limit) ⇒ Object
Identifies byte windows that are “entropic” (< limit repeats of any byte) Algorithm adapted from aeskeyfind.c
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/memorandom/plugins/aes.rb', line 106 def entropic(buff, window, limit) bytes = buff.unpack("C*") index = 0 while index < (bytes.length - window) counts = BYTE_VALUES.dup index.upto(index+window) {|offset| counts[ bytes[offset] ] += 1 } mvalue = counts.max if mvalue < limit yield(index) # Key-hunting time, skip ahead by one byte only index += 1 else # Not entropic, skip ahead by at least max - limit index += ((mvalue + 1) - limit) end end end |
#scan(buffer, source_offset) ⇒ Object
Scan takes a buffer and an offset of where this buffer starts in the source
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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/memorandom/plugins/aes.rb', line 127 def scan(buffer, source_offset) blen = buffer.length entropic(buffer, AES_KEYBLOCK_MIN, ENTROPIC_MIN) do |i| # Exit if we dont have at least 240 bytes left return if (i + 240) > blen # Create a byte map to work in both little and big endian formats #["V", "N"].each do |endian| ["V"].each do |endian| bmap = buffer[i, 240].unpack("#{endian}*") # Check distance from 256-bit AES key xor_count_256 = 0 1.upto(7) do |row| 0.upto(7) do |column| break if (row == 7 and column == 4) case column when 0 xor_count_256 += aes_popcount( aes_key_core( bmap[8*row-1], row) ^ bmap[8*(row-1)] ^ bmap[8*row] ) when 4 xor_count_256 += aes_popcount( aes_sbox_bytes( bmap[8*row+3]) ^ bmap[8*(row-1)+4] ^ bmap[8*row+4]) else xor_count_256 += aes_popcount( bmap[8*row+column-1] ^ bmap[8*(row-1)+column] ^ bmap[8*row + column]) end end end # We found a possible AES-256 key unless xor_count_256 > AES_XOR_LIMIT report_hit(:type => "Key(AES-256)", :data => bmap[0, 256/32].pack("#{endian}*").unpack("C*").map{|x| "%.2x" % x }.join, :offset => source_offset + i) next end # Check distance from 128-bit AES key xor_count_128 = 0 1.upto(10) do |row| 0.upto(3) do |column| before_count = xor_count_128 case column when 0 xor_count_128 += aes_popcount( aes_key_core( bmap[4*row-1],row) ^ bmap[4*(row-1)] ^ bmap[4*row]) else xor_count_128 += aes_popcount( (bmap[4*row + column-1] ^ bmap[4*(row-1)+column]) ^ bmap[4*row + column]) end end end # We found a possible AES-128 key unless xor_count_128 > AES_XOR_LIMIT report_hit(:type => "Key(AES-128)", :data => bmap[0, 128/32].pack("#{endian}*").unpack("C*").map{|x| "%.2x" % x }.join, :offset => source_offset + i) end end end end |