Class: Megar::Crypto::AesCtr

Inherits:
Object
  • Object
show all
Defined in:
lib/megar/crypto/aes_ctr.rb

Overview

Implements AES COUNTER mode using base AES CBC implementation provided by OpenSSL

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ AesCtr

Consturcts a new AES CTR-mode object give options options = encryption key as binary string or array of 32-bit integer (required) options = initialisation vector as array of 32-bit integer (nulled by default)



10
11
12
13
# File 'lib/megar/crypto/aes_ctr.rb', line 10

def initialize(options={})
  self.key = options[:key]
  self.iv = options[:iv]
end

Instance Attribute Details

#ivObject

Returns the value of attribute iv.



5
6
7
# File 'lib/megar/crypto/aes_ctr.rb', line 5

def iv
  @iv
end

#keyObject

Returns the value of attribute key.



4
5
6
# File 'lib/megar/crypto/aes_ctr.rb', line 4

def key
  @key
end

Instance Method Details

#a32_to_str(a) ⇒ Object

TODO: refactor to pull this method from a shared lib.



69
70
71
72
73
# File 'lib/megar/crypto/aes_ctr.rb', line 69

def a32_to_str(a)
  b = ''
  (a.size * 4).times { |i| b << ((a[i>>2] >> (24-(i & 3)*8)) & 255).chr }
  b
end

#packingObject



15
16
17
# File 'lib/megar/crypto/aes_ctr.rb', line 15

def packing
  'l>*'
end

#str_to_a32(b, signed = true) ⇒ Object

TODO: refactor to pull this method from a shared lib.



58
59
60
61
62
63
64
65
66
# File 'lib/megar/crypto/aes_ctr.rb', line 58

def str_to_a32(b,signed=true)
  a = Array.new((b.length+3) >> 2,0)
  b.length.times { |i| a[i>>2] |= (b.getbyte(i) << (24-(i & 3)*8)) }
  if signed
    a.pack('l>*').unpack('l>*')
  else
    a
  end
end

#update(chunk) ⇒ Object

Returns the encrypted binary string of chunk (provided as binary string). Repeated calls will continue the counter sequence.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/megar/crypto/aes_ctr.rb', line 29

def update(chunk)
  a32 = str_to_a32(chunk)
  last_i = 0

  (0..a32.size - 3).step(4) do |i|
    enc = Megar::Crypto::Aes.new(key: key).encrypt(iv)
    4.times do |m|
      a32[i+m] = (a32[i+m] || 0) ^ (enc[m] || 0)
    end
    iv[3] += 1
    iv[2] += 1 if iv[3] == 0
    last_i = i + 4
  end

  remainder = a32.size % 4

  if remainder > 0
    v = [0, 0, 0, 0]
    (last_i..a32.size - 1).step(1) { |m| v[m-last_i] = a32[m] || 0 }
    enc = Megar::Crypto::Aes.new(key: key).encrypt(iv)
    4.times { |m| v[m] = v[m] ^ enc[m] }

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

  a32_to_str(a32)[0..chunk.size - 1]
end