Method: Rmega::Crypto::AesCtr#decrypt

Defined in:
lib/rmega/crypto/aes_ctr.rb

#decrypt(key, nonce, data) ⇒ Object



9
10
11
12
13
14
15
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/rmega/crypto/aes_ctr.rb', line 9

def decrypt(key, nonce, data)
  raise "invalid nonce" if nonce.size != 4 or !nonce.respond_to?(:pack)
  raise "invalid key" if key.size != 4 or !key.respond_to?(:pack)

  mac = [nonce[0], nonce[1], nonce[0], nonce[1]]
  enc = nil
  a32 = Utils.str_to_a32 data
  len = a32.size - 3
  last_i = 0

  (0..len).step(4) do |i|
    enc = Aes.encrypt key, nonce
    4.times do |m|
      a32[i+m] = (a32[i+m] || 0) ^ (enc[m] || 0)
      mac[m] = (mac[m] || 0) ^ (a32[i+m] || 0)
    end
    mac = Aes.encrypt key, mac
    nonce[3] += 1
    nonce[2] += 1 if nonce[3] == 0
    last_i = i + 4
  end

  if last_i < a32.size
    v = [0, 0, 0, 0]
    (last_i..a32.size - 1).step(1) { |m| v[m-last_i] = a32[m] || 0 }

    enc = Aes.encrypt key, nonce
    4.times { |m| v[m] = v[m] ^ enc[m] }

    j = data.size & 15
    m = Utils.str_to_a32 Array.new(j+1).join(255.chr)+Array.new(17-j).join(0.chr)

    4.times { |x| mac[x] = mac[x] ^ (v[x] & m[x]) }

    mac = Aes.encrypt key, mac

    (last_i..a32.size - 1).step(1) { |j| a32[j] = v[j - last_i] || 0 }
  end

  decrypted_data = Utils.a32_to_str(a32, data.size)

  {data: decrypted_data, mac: mac}
end