crypt19-rb 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ class String
2
+ if RUBY_VERSION =~ /1\.8/
3
+ def getbyte(index)
4
+ self[index]
5
+ end
6
+ end
7
+
8
+ if RUBY_VERSION =~ /1\.8/ && RUBY_VERSION != '1.8.7'
9
+ def bytes
10
+ bytes = []
11
+ self.each_byte {|b| bytes << b}
12
+ bytes
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,119 @@
1
+ require 'stringio'
2
+ require 'crypt/stringxor'
3
+
4
+ module Crypt
5
+ module CBC
6
+
7
+ ULONG = 0x100000000
8
+
9
+ # When this module is mixed in with an encryption class, the class
10
+ # must provide three methods: encrypt_block(block) and decrypt_block(block)
11
+ # and block_size()
12
+
13
+
14
+ def generate_initialization_vector(words)
15
+ srand(Time.now.to_i)
16
+ vector = ""
17
+ words.times {
18
+ vector << [rand(ULONG)].pack('N')
19
+ }
20
+ return(vector)
21
+ end
22
+
23
+
24
+ def encrypt_stream(plain_stream, crypt_stream)
25
+ # Cypher-block-chain mode
26
+
27
+ init_vector = generate_initialization_vector(block_size() / 4)
28
+ chain = encrypt_block(init_vector)
29
+ crypt_stream.write(chain)
30
+
31
+ while ((block = plain_stream.read(block_size())) && (block.length == block_size()))
32
+ block = block ^ chain
33
+ encrypted = encrypt_block(block)
34
+ crypt_stream.write(encrypted)
35
+ chain = encrypted
36
+ end
37
+
38
+ # write the final block
39
+ # At most block_size()-1 bytes can be part of the message.
40
+ # That means the final byte can be used to store the number of meaningful
41
+ # bytes in the final block
42
+ block = '' if block.nil?
43
+ buffer = block.split('')
44
+ remaining_message_bytes = block_size() - buffer.length
45
+ buffer << remaining_message_bytes.chr * remaining_message_bytes
46
+ block = buffer.join('')
47
+ block = block ^ chain
48
+ encrypted = encrypt_block(block)
49
+ crypt_stream.write(encrypted)
50
+ end
51
+
52
+
53
+ def decrypt_stream(crypt_stream, plain_stream)
54
+ # Cypher-block-chain mode
55
+ chain = crypt_stream.read(block_size())
56
+
57
+ while (block = crypt_stream.read(block_size()))
58
+ decrypted = decrypt_block(block)
59
+ plain_text = decrypted ^ chain
60
+ plain_stream.write(plain_text) unless crypt_stream.eof?
61
+ chain = block
62
+ end
63
+
64
+ # write the final block, omitting the padding
65
+ buffer = plain_text.split('')
66
+ remaining_message_bytes = block_size() - buffer.last.unpack('C').first
67
+ remaining_message_bytes.times { plain_stream.write(buffer.shift) }
68
+ end
69
+
70
+
71
+ def carefully_open_file(filename, mode)
72
+ begin
73
+ a_file = File.new(filename, mode)
74
+ rescue
75
+ puts "Sorry. There was a problem opening the file <#{filename}>."
76
+ a_file.close() unless a_file.nil?
77
+ raise
78
+ end
79
+ return(a_file)
80
+ end
81
+
82
+
83
+ def encrypt_file(plain_filename, crypt_filename)
84
+ plain_file = carefully_open_file(plain_filename, 'rb')
85
+ crypt_file = carefully_open_file(crypt_filename, 'wb+')
86
+ encrypt_stream(plain_file, crypt_file)
87
+ plain_file.close unless plain_file.closed?
88
+ crypt_file.close unless crypt_file.closed?
89
+ end
90
+
91
+
92
+ def decrypt_file(crypt_filename, plain_filename)
93
+ crypt_file = carefully_open_file(crypt_filename, 'rb')
94
+ plain_file = carefully_open_file(plain_filename, 'wb+')
95
+ decrypt_stream(crypt_file, plain_file)
96
+ crypt_file.close unless crypt_file.closed?
97
+ plain_file.close unless plain_file.closed?
98
+ end
99
+
100
+
101
+ def encrypt_string(plain_text)
102
+ plain_stream = StringIO.new(plain_text)
103
+ crypt_stream = StringIO.new('')
104
+ encrypt_stream(plain_stream, crypt_stream)
105
+ crypt_text = crypt_stream.string
106
+ return(crypt_text)
107
+ end
108
+
109
+
110
+ def decrypt_string(crypt_text)
111
+ crypt_stream = StringIO.new(crypt_text)
112
+ plain_stream = StringIO.new('')
113
+ decrypt_stream(crypt_stream, plain_stream)
114
+ plain_text = plain_stream.string
115
+ return(plain_text)
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,138 @@
1
+ # adapted from C++ code written by Wei Dai
2
+ # of the Crypto++ project http://www.eskimo.com/~weidai/cryptlib.html
3
+
4
+ require 'crypt/cbc'
5
+
6
+ module Crypt
7
+ class Gost
8
+
9
+ include CBC
10
+
11
+ ULONG = 0x100000000
12
+
13
+ def block_size
14
+ return(8)
15
+ end
16
+
17
+
18
+ def initialize(user_key)
19
+
20
+ # These are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
21
+ @sBox = [
22
+ [4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],
23
+ [14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],
24
+ [5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],
25
+ [7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],
26
+ [6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],
27
+ [4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],
28
+ [13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],
29
+ [1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12]
30
+ ]
31
+
32
+ # These are the S-boxes given in the GOST source code listing in Applied
33
+ # Cryptography 2nd Ed., p. 644. They appear to be from the DES S-boxes
34
+ # [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 ],
35
+ # [ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 ],
36
+ # [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 ],
37
+ # [ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 ],
38
+ # [ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 ],
39
+ # [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 ],
40
+ # [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 ],
41
+ # [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 ]
42
+
43
+ # precalculate the S table
44
+ @s_table = precalculate_s_table()
45
+
46
+ # derive the 32-byte key from the user-supplied key
47
+ user_key_length = user_key.length
48
+ @key = user_key[0..31].unpack('C'*32)
49
+ if (user_key_length < 32)
50
+ user_key_length.upto(31) { @key << 0 }
51
+ end
52
+ end
53
+
54
+
55
+ def precalculate_s_table()
56
+ s_table = [[], [], [], []]
57
+ 0.upto(3) { |i|
58
+ 0.upto(255) { |j|
59
+ t = @sBox[2*i][j % 16] | (@sBox[2*i+1][j/16] << 4)
60
+ u = (8*i + 11) % 32
61
+ v = (t << u) | (t >> (32-u))
62
+ s_table[i][j] = (v % ULONG)
63
+ }
64
+ }
65
+ return(s_table)
66
+ end
67
+
68
+
69
+ def f(long_word)
70
+ long_word = long_word % ULONG
71
+ a, b, c, d = [long_word].pack('L').unpack('CCCC')
72
+ return(@s_table[3][d] ^ @s_table[2][c] ^ @s_table[1][b] ^ @s_table[0][a])
73
+ end
74
+
75
+
76
+ def encrypt_pair(xl, xr)
77
+ 3.times {
78
+ xr ^= f(xl+@key[0])
79
+ xl ^= f(xr+@key[1])
80
+ xr ^= f(xl+@key[2])
81
+ xl ^= f(xr+@key[3])
82
+ xr ^= f(xl+@key[4])
83
+ xl ^= f(xr+@key[5])
84
+ xr ^= f(xl+@key[6])
85
+ xl ^= f(xr+@key[7])
86
+ }
87
+ xr ^= f(xl+@key[7])
88
+ xl ^= f(xr+@key[6])
89
+ xr ^= f(xl+@key[5])
90
+ xl ^= f(xr+@key[4])
91
+ xr ^= f(xl+@key[3])
92
+ xl ^= f(xr+@key[2])
93
+ xr ^= f(xl+@key[1])
94
+ xl ^= f(xr+@key[0])
95
+ return([xr, xl])
96
+ end
97
+
98
+
99
+ def decrypt_pair(xl, xr)
100
+ xr ^= f(xl+@key[0])
101
+ xl ^= f(xr+@key[1])
102
+ xr ^= f(xl+@key[2])
103
+ xl ^= f(xr+@key[3])
104
+ xr ^= f(xl+@key[4])
105
+ xl ^= f(xr+@key[5])
106
+ xr ^= f(xl+@key[6])
107
+ xl ^= f(xr+@key[7])
108
+ 3.times {
109
+ xr ^= f(xl+@key[7])
110
+ xl ^= f(xr+@key[6])
111
+ xr ^= f(xl+@key[5])
112
+ xl ^= f(xr+@key[4])
113
+ xr ^= f(xl+@key[3])
114
+ xl ^= f(xr+@key[2])
115
+ xr ^= f(xl+@key[1])
116
+ xl ^= f(xr+@key[0])
117
+ }
118
+ return([xr, xl])
119
+ end
120
+
121
+
122
+ def encrypt_block(block)
123
+ xl, xr = block.unpack('NN')
124
+ xl, xr = encrypt_pair(xl, xr)
125
+ encrypted = [xl, xr].pack('NN')
126
+ return(encrypted)
127
+ end
128
+
129
+
130
+ def decrypt_block(block)
131
+ xl, xr = block.unpack('NN')
132
+ xl, xr = decrypt_pair(xl, xr)
133
+ decrypted = [xl, xr].pack('NN')
134
+ return(decrypted)
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,190 @@
1
+ # IDEA (International Data Encryption Algorithm) by
2
+ # Xuejia Lai and James Massey (1992). Refer to license info at the end of this file.
3
+
4
+ require 'digest/md5'
5
+ require 'crypt/cbc'
6
+
7
+ module Crypt
8
+ class IDEA
9
+
10
+ include Crypt::CBC
11
+
12
+ ULONG = 0x100000000
13
+ USHORT = 0x10000
14
+
15
+ ENCRYPT = 0
16
+ DECRYPT = 1
17
+
18
+
19
+ def block_size
20
+ return(8)
21
+ end
22
+
23
+
24
+ def initialize(key128, mode)
25
+ # IDEA is subject to attack unless the key is sufficiently random, so we
26
+ # take an MD5 digest of a variable-length passphrase to ensure a solid key
27
+ if (key128.class == String)
28
+ digest = Digest::MD5.digest(key128)
29
+ key128 = digest.unpack('n'*8)
30
+ end
31
+ raise "Key must be 128 bits (8 words)" unless (key128.class == Array) && (key128.length == 8)
32
+ raise "Mode must be IDEA::ENCRYPT or IDEA::DECRYPT" unless ((mode == ENCRYPT) | (mode == DECRYPT))
33
+ if (mode == ENCRYPT)
34
+ @subkeys = generate_encryption_subkeys(key128)
35
+ else (mode == DECRYPT)
36
+ @subkeys = generate_decryption_subkeys(key128)
37
+ end
38
+ end
39
+
40
+
41
+ def mul(a, b)
42
+ modulus = 0x10001
43
+ return((1 - b) % USHORT) if (a == 0)
44
+ return((1 - a) % USHORT) if (b == 0)
45
+ return((a * b) % modulus)
46
+ end
47
+
48
+
49
+ def mul_inv(x)
50
+ modulus = 0x10001
51
+ x = x.to_i % USHORT
52
+ return(x) if (x <= 1)
53
+ t1 = USHORT / x
54
+ y = modulus % x
55
+ if (y == 1)
56
+ inv = (1 - t1) & 0xFFFF
57
+ return(inv)
58
+ end
59
+ t0 = 1
60
+ while (y != 1)
61
+ q = x / y
62
+ x = x % y
63
+ t0 = t0 + (q * t1)
64
+ return(t0) if (x == 1)
65
+ q = y / x
66
+ y = y % x
67
+ t1 = t1 + (q * t0)
68
+ end
69
+ inv = (1 - t1) & 0xFFFF
70
+ return(inv)
71
+ end
72
+
73
+
74
+ def generate_encryption_subkeys(key)
75
+ encrypt_keys = []
76
+ encrypt_keys[0..7] = key.dup
77
+ 8.upto(51) { |i|
78
+ a = ((i + 1) % 8 > 0) ? (i-7) : (i-15)
79
+ b = ((i + 2) % 8 < 2) ? (i-14) : (i-6)
80
+ encrypt_keys[i] = ((encrypt_keys[a] << 9) | (encrypt_keys[b] >> 7)) % USHORT
81
+ }
82
+ return(encrypt_keys)
83
+ end
84
+
85
+
86
+ def generate_decryption_subkeys(key)
87
+ encrypt_keys = generate_encryption_subkeys(key)
88
+ decrypt_keys = []
89
+ decrypt_keys[48] = mul_inv(encrypt_keys.shift)
90
+ decrypt_keys[49] = (-encrypt_keys.shift) % USHORT
91
+ decrypt_keys[50] = (-encrypt_keys.shift) % USHORT
92
+ decrypt_keys[51] = mul_inv(encrypt_keys.shift)
93
+ 42.step(0, -6) { |i|
94
+ decrypt_keys[i+4] = encrypt_keys.shift % USHORT
95
+ decrypt_keys[i+5] = encrypt_keys.shift % USHORT
96
+ decrypt_keys[i] = mul_inv(encrypt_keys.shift)
97
+ if (i ==0)
98
+ decrypt_keys[1] = (-encrypt_keys.shift) % USHORT
99
+ decrypt_keys[2] = (-encrypt_keys.shift) % USHORT
100
+ else
101
+ decrypt_keys[i+2] = (-encrypt_keys.shift) % USHORT
102
+ decrypt_keys[i+1] = (-encrypt_keys.shift) % USHORT
103
+ end
104
+ decrypt_keys[i+3] = mul_inv(encrypt_keys.shift)
105
+ }
106
+ return(decrypt_keys)
107
+ end
108
+
109
+
110
+ def crypt_pair(l, r)
111
+ word = [l, r].pack('NN').unpack('nnnn')
112
+ k = @subkeys[0..51]
113
+ 8.downto(1) { |i|
114
+ word[0] = mul(word[0], k.shift)
115
+ word[1] = (word[1] + k.shift) % USHORT
116
+ word[2] = (word[2] + k.shift) % USHORT
117
+ word[3] = mul(word[3], k.shift)
118
+ t2 = word[0] ^ word[2]
119
+ t2 = mul(t2, k.shift)
120
+ t1 = (t2 + (word[1] ^ word[3])) % USHORT
121
+ t1 = mul(t1, k.shift)
122
+ t2 = (t1 + t2) % USHORT
123
+ word[0] ^= t1
124
+ word[3] ^= t2
125
+ t2 ^= word[1]
126
+ word[1] = word[2] ^ t1
127
+ word[2] = t2
128
+ }
129
+ result = []
130
+ result << mul(word[0], k.shift)
131
+ result << (word[2] + k.shift) % USHORT
132
+ result << (word[1] + k.shift) % USHORT
133
+ result << mul(word[3], k.shift)
134
+ two_longs = result.pack('nnnn').unpack('NN')
135
+ return(two_longs)
136
+ end
137
+
138
+ def encrypt_block(block)
139
+ xl, xr = block.unpack('NN')
140
+ xl, xr = crypt_pair(xl, xr)
141
+ encrypted = [xl, xr].pack('NN')
142
+ return(encrypted)
143
+ end
144
+
145
+
146
+ def decrypt_block(block)
147
+ xl, xr = block.unpack('NN')
148
+ xl, xr = crypt_pair(xl, xr)
149
+ decrypted = [xl, xr].pack('NN')
150
+ return(decrypted)
151
+ end
152
+
153
+
154
+ end
155
+ end
156
+
157
+
158
+ # IDEA LICENSE INFORMATION
159
+ #
160
+ # This software product contains the IDEA algorithm as described and claimed in
161
+ # US patent 5,214,703, EPO patent 0482154 (covering Austria, France, Germany,
162
+ # Italy, the Netherlands, Spain, Sweden, Switzerland, and the UK), and Japanese
163
+ # patent application 508119/1991, "Device for the conversion of a digital block
164
+ # and use of same" (hereinafter referred to as "the algorithm"). Any use of
165
+ # the algorithm for commercial purposes is thus subject to a license from Ascom
166
+ # Systec Ltd. of CH-5506 Maegenwil (Switzerland), being the patentee and sole
167
+ # owner of all rights, including the trademark IDEA.
168
+ #
169
+ # Commercial purposes shall mean any revenue generating purpose including but
170
+ # not limited to:
171
+ #
172
+ # i) Using the algorithm for company internal purposes (subject to a site
173
+ # license).
174
+ #
175
+ # ii) Incorporating the algorithm into any software and distributing such
176
+ # software and/or providing services relating thereto to others (subject to
177
+ # a product license).
178
+ #
179
+ # iii) Using a product containing the algorithm not covered by an IDEA license
180
+ # (subject to an end user license).
181
+ #
182
+ # All such end user license agreements are available exclusively from Ascom
183
+ # Systec Ltd and may be requested via the WWW at http://www.ascom.ch/systec or
184
+ # by email to idea@ascom.ch.
185
+ #
186
+ # Use other than for commercial purposes is strictly limited to non-revenue
187
+ # generating data transfer between private individuals. The use by government
188
+ # agencies, non-profit organizations, etc is considered as use for commercial
189
+ # purposes but may be subject to special conditions. Any misuse will be
190
+ # prosecuted.