Class: Memorandom::Plugins::AES

Inherits:
Memorandom::PluginTemplate show all
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

#hits, #scanner

Instance Method Summary collapse

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