otherinbox-crypt19 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 = buffer.length
45
+ buffer << remaining_message_bytes.chr * (block_size() - 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 = 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.
@@ -0,0 +1,92 @@
1
+ # add_noise - take a message and intersperse noise to make a new noisy message of given byte-length
2
+ # remove_noise - take a noisy message and extract the message
3
+
4
+ module Crypt
5
+ module Noise
6
+
7
+ def add_noise(new_length)
8
+ message = self
9
+ usable_noisy_message_length = new_length / 9 * 8
10
+ bitmap_size = new_length / 9
11
+ remaining_bytes = new_length - usable_noisy_message_length - bitmap_size
12
+ if (message.length > usable_noisy_message_length)
13
+ minimumnew_length = (message.length / 8.0).ceil * 9
14
+ puts "For a clear text of #{message.length} bytes, the minimum obscured length"
15
+ puts "is #{minimumnew_length} bytes which allows for no noise in the message."
16
+ puts "You should choose an obscured length of at least double the clear text"
17
+ puts "length, such as #{message.length / 8 * 32} bytes"
18
+ raise "Insufficient length for noisy message"
19
+ end
20
+ bitmap = []
21
+ usable_noisy_message_length.times { bitmap << false }
22
+ srand(Time.now.to_i)
23
+ positions_selected = 0
24
+ while (positions_selected < message.length)
25
+ position_taken = rand(usable_noisy_message_length)
26
+ if bitmap[position_taken]
27
+ next
28
+ else
29
+ bitmap[position_taken] = true
30
+ positions_selected = positions_selected.next
31
+ end
32
+ end
33
+
34
+ noisy_message = ""
35
+ 0.upto(bitmap_size-1) { |byte|
36
+ c = 0
37
+ 0.upto(7) { |bit|
38
+ c = c + (1<<bit) if bitmap[byte * 8 + bit]
39
+ }
40
+ noisy_message << c.chr
41
+ }
42
+ pos_in_message = 0
43
+ 0.upto(usable_noisy_message_length-1) { |pos|
44
+ if bitmap[pos]
45
+ meaningful_byte = message[pos_in_message]
46
+ noisy_message << meaningful_byte
47
+ pos_in_message = pos_in_message.next
48
+ else
49
+ noise_byte = rand(256).chr
50
+ noisy_message << noise_byte
51
+ end
52
+ }
53
+ remaining_bytes.times {
54
+ noise_byte = rand(256).chr
55
+ noisy_message << noise_byte
56
+ }
57
+ return(noisy_message)
58
+ end
59
+
60
+
61
+ def remove_noise
62
+ noisy_message = self
63
+ bitmap_size = noisy_message.length / 9
64
+ actual_message_length = bitmap_size * 8
65
+
66
+ actual_message_start = bitmap_size
67
+ actual_message_finish = bitmap_size + actual_message_length - 1
68
+ actual_message = noisy_message[actual_message_start..actual_message_finish]
69
+
70
+ bitmap = []
71
+ 0.upto(bitmap_size - 1) { |byte|
72
+ c = noisy_message[byte]
73
+ 0.upto(7) { |bit|
74
+ bitmap[byte * 8 + bit] = (c[bit] == 1)
75
+ }
76
+ }
77
+ clear_message = ""
78
+ 0.upto(actual_message_length) { |pos|
79
+ meaningful = bitmap[pos]
80
+ if meaningful
81
+ clear_message << actual_message[pos]
82
+ end
83
+ }
84
+ return(clear_message)
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ class String
91
+ include Crypt::Noise
92
+ end