8: def self.extended(orig)
9: orig.instance_eval {
10: @remaining = ""
11: @counter = nil
12: @counter_len = orig.block_size
13: orig.encrypt
14: orig.padding = 0
15: }
16:
17: class <<orig
18: alias :_update :update
19: private :_update
20: undef :update
21:
22: def iv
23: @counter
24: end
25:
26: def iv_len
27: block_size
28: end
29:
30: def iv=(iv_s)
31: @counter = iv_s if @counter.nil?
32: end
33:
34: def encrypt
35:
36: end
37:
38: def decrypt
39:
40: end
41:
42: def padding=(pad)
43:
44: end
45:
46: def reset
47: @remaining = ""
48: end
49:
50: def update(data)
51: @remaining += data
52:
53: encrypted = ""
54:
55: while @remaining.bytesize >= block_size
56: encrypted += xor!(@remaining.slice!(0, block_size),
57: _update(@counter))
58: increment_counter!
59: end
60:
61: encrypted
62: end
63:
64: def final
65: unless @remaining.empty?
66: s = xor!(@remaining, _update(@counter))
67: else
68: s = ""
69: end
70:
71: @remaining = ""
72:
73: s
74: end
75:
76: private
77:
78: def xor!(s1, s2)
79: s = []
80: s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a^b) }
81: s.pack('Q*')
82: end
83:
84: def increment_counter!
85: c = @counter_len
86: while ((c -= 1) > 0)
87: if @counter.setbyte(c, (@counter.getbyte(c) + 1) & 0xff) != 0
88: break
89: end
90: end
91: end
92: end
93: end