crypt 1.1.4 → 2.0
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.
- checksums.yaml +7 -0
- data/crypt/blowfish.rb +25 -23
- data/crypt/cbc.rb +26 -28
- data/crypt/idea.rb +30 -31
- data/crypt/noise.rb +10 -10
- data/crypt/rijndael.rb +55 -50
- data/crypt/stringxor.rb +6 -6
- data/test/test-blowfish.rb +14 -13
- data/test/test-gost.rb +13 -11
- data/test/test-idea.rb +22 -19
- data/test/test-rijndael.rb +29 -27
- metadata +56 -49
- data/crypt/purerubystringio.rb +0 -378
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 52adac97c724e6cda38884007042b2eda55fc299
|
4
|
+
data.tar.gz: a017aaec965e38ea808116495ddc84ed94048f94
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 97bb5b0bed207146235d0285d78c6435cee219544eee140c8c9aa86b7d70b7437ad657d930f44a3cdaa3face1ef937f62ff16e58e6dd58daa3b84a088714050b
|
7
|
+
data.tar.gz: 51fec804a2c85eba54a33c81ee4b980636cb9a8e6015c033260acc26812eac511d99f569f13f7802b776038e0bb760cf71ad3f4d8d73ecd1b14e49a9960e79ce
|
data/crypt/blowfish.rb
CHANGED
@@ -5,20 +5,15 @@
|
|
5
5
|
|
6
6
|
module Crypt
|
7
7
|
class Blowfish
|
8
|
-
|
8
|
+
|
9
9
|
require 'crypt/cbc'
|
10
10
|
include Crypt::CBC
|
11
|
-
|
11
|
+
|
12
12
|
require 'crypt/blowfish-tables'
|
13
13
|
include Crypt::BlowfishTables
|
14
|
-
|
14
|
+
|
15
15
|
ULONG = 0x100000000
|
16
|
-
|
17
|
-
def block_size
|
18
|
-
return(8)
|
19
|
-
end
|
20
|
-
|
21
|
-
|
16
|
+
|
22
17
|
def initialize(key)
|
23
18
|
@key = key
|
24
19
|
raise "Bad key length: the key must be 1-56 bytes." unless (key.length.between?(1,56))
|
@@ -26,8 +21,11 @@ class Blowfish
|
|
26
21
|
@sBoxes = []
|
27
22
|
setup_blowfish()
|
28
23
|
end
|
29
|
-
|
30
|
-
|
24
|
+
|
25
|
+
def block_size()
|
26
|
+
8
|
27
|
+
end
|
28
|
+
|
31
29
|
def f(x)
|
32
30
|
a, b, c, d = [x].pack('N').unpack('CCCC')
|
33
31
|
y = (@sBoxes[0][a] + @sBoxes[1][b]) % ULONG
|
@@ -35,8 +33,8 @@ class Blowfish
|
|
35
33
|
y = (y + @sBoxes[3][d]) % ULONG
|
36
34
|
return(y)
|
37
35
|
end
|
38
|
-
|
39
|
-
|
36
|
+
|
37
|
+
|
40
38
|
def setup_blowfish()
|
41
39
|
@sBoxes = Array.new(4) { |i| INITIALSBOXES[i].clone }
|
42
40
|
@pArray = INITIALPARRAY.clone
|
@@ -44,7 +42,8 @@ class Blowfish
|
|
44
42
|
0.upto(17) { |i|
|
45
43
|
data = 0
|
46
44
|
4.times {
|
47
|
-
|
45
|
+
k = @key[keypos].ord() # ruby 2.0
|
46
|
+
data = ((data << 8) | k) % ULONG
|
48
47
|
keypos = (keypos.next) % @key.length
|
49
48
|
}
|
50
49
|
@pArray[i] = (@pArray[i] ^ data) % ULONG
|
@@ -64,7 +63,7 @@ class Blowfish
|
|
64
63
|
}
|
65
64
|
}
|
66
65
|
end
|
67
|
-
|
66
|
+
|
68
67
|
def encrypt_pair(xl, xr)
|
69
68
|
0.upto(15) { |i|
|
70
69
|
xl = (xl ^ @pArray[i]) % ULONG
|
@@ -76,8 +75,8 @@ class Blowfish
|
|
76
75
|
xl = (xl ^ @pArray[17]) % ULONG
|
77
76
|
return([xl, xr])
|
78
77
|
end
|
79
|
-
|
80
|
-
|
78
|
+
|
79
|
+
|
81
80
|
def decrypt_pair(xl, xr)
|
82
81
|
17.downto(2) { |i|
|
83
82
|
xl = (xl ^ @pArray[i]) % ULONG
|
@@ -89,22 +88,25 @@ class Blowfish
|
|
89
88
|
xl = (xl ^ @pArray[0]) % ULONG
|
90
89
|
return([xl, xr])
|
91
90
|
end
|
92
|
-
|
93
|
-
|
91
|
+
|
92
|
+
|
94
93
|
def encrypt_block(block)
|
94
|
+
block = block.force_encoding("ASCII-8BIT") # to treat unicode characters as two bytes
|
95
|
+
raise "block must be #{block_size()} bytes long" if (block.length() != block_size())
|
95
96
|
xl, xr = block.unpack('NN')
|
96
97
|
xl, xr = encrypt_pair(xl, xr)
|
97
98
|
encrypted = [xl, xr].pack('NN')
|
98
99
|
return(encrypted)
|
99
100
|
end
|
100
|
-
|
101
|
-
|
101
|
+
|
102
|
+
|
102
103
|
def decrypt_block(block)
|
104
|
+
raise "block must be #{block_size()} bytes long" if (block.length() != block_size())
|
103
105
|
xl, xr = block.unpack('NN')
|
104
106
|
xl, xr = decrypt_pair(xl, xr)
|
105
107
|
decrypted = [xl, xr].pack('NN')
|
106
108
|
return(decrypted)
|
107
109
|
end
|
108
|
-
|
110
|
+
|
111
|
+
end
|
109
112
|
end
|
110
|
-
end
|
data/crypt/cbc.rb
CHANGED
@@ -2,43 +2,42 @@
|
|
2
2
|
|
3
3
|
module Crypt
|
4
4
|
module CBC
|
5
|
-
|
5
|
+
|
6
6
|
require 'stringio'
|
7
7
|
require 'crypt/stringxor'
|
8
|
-
|
8
|
+
|
9
9
|
ULONG = 0x100000000
|
10
|
-
|
10
|
+
|
11
11
|
# When this module is mixed in with an encryption class, the class
|
12
12
|
# must provide three methods: encrypt_block(block) and decrypt_block(block)
|
13
13
|
# and block_size()
|
14
|
-
|
15
|
-
|
14
|
+
|
15
|
+
|
16
16
|
def generate_initialization_vector(words)
|
17
17
|
srand(Time.now.to_i)
|
18
|
-
vector = ""
|
18
|
+
vector = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode
|
19
19
|
words.times {
|
20
20
|
vector << [rand(ULONG)].pack('N')
|
21
21
|
}
|
22
22
|
return(vector)
|
23
23
|
end
|
24
|
-
|
25
|
-
|
24
|
+
|
25
|
+
|
26
26
|
def encrypt_stream(plainStream, cryptStream)
|
27
27
|
# Cypher-block-chain mode
|
28
|
-
|
28
|
+
|
29
29
|
initVector = generate_initialization_vector(block_size() / 4)
|
30
30
|
chain = encrypt_block(initVector)
|
31
31
|
cryptStream.write(chain)
|
32
32
|
|
33
33
|
while ((block = plainStream.read(block_size())) && (block.length == block_size()))
|
34
|
-
block = block ^ chain
|
34
|
+
block = block ^ chain
|
35
35
|
encrypted = encrypt_block(block)
|
36
36
|
cryptStream.write(encrypted)
|
37
37
|
chain = encrypted
|
38
38
|
end
|
39
|
-
|
40
39
|
# write the final block
|
41
|
-
# At most block_size()-1 bytes can be part of the message.
|
40
|
+
# At most block_size()-1 bytes can be part of the message.
|
42
41
|
# That means the final byte can be used to store the number of meaningful
|
43
42
|
# bytes in the final block
|
44
43
|
block = '' if block.nil?
|
@@ -52,8 +51,8 @@ module CBC
|
|
52
51
|
encrypted = encrypt_block(block)
|
53
52
|
cryptStream.write(encrypted)
|
54
53
|
end
|
55
|
-
|
56
|
-
|
54
|
+
|
55
|
+
|
57
56
|
def decrypt_stream(cryptStream, plainStream)
|
58
57
|
# Cypher-block-chain mode
|
59
58
|
chain = cryptStream.read(block_size())
|
@@ -64,26 +63,25 @@ module CBC
|
|
64
63
|
plainStream.write(plainText) unless cryptStream.eof?
|
65
64
|
chain = block
|
66
65
|
end
|
67
|
-
|
68
66
|
# write the final block, omitting the padding
|
69
67
|
buffer = plainText.split('')
|
70
68
|
remainingMessageBytes = buffer.last.unpack('C').first
|
71
69
|
remainingMessageBytes.times { plainStream.write(buffer.shift) }
|
72
70
|
end
|
73
|
-
|
74
|
-
|
71
|
+
|
72
|
+
|
75
73
|
def carefully_open_file(filename, mode)
|
76
74
|
begin
|
77
75
|
aFile = File.new(filename, mode)
|
78
76
|
rescue
|
79
77
|
puts "Sorry. There was a problem opening the file <#{filename}>."
|
80
|
-
aFile.close() unless aFile.nil?
|
78
|
+
aFile.close() unless aFile.nil? || aFile.closed?
|
81
79
|
raise
|
82
80
|
end
|
83
81
|
return(aFile)
|
84
82
|
end
|
85
|
-
|
86
|
-
|
83
|
+
|
84
|
+
|
87
85
|
def encrypt_file(plainFilename, cryptFilename)
|
88
86
|
plainFile = carefully_open_file(plainFilename, 'rb')
|
89
87
|
cryptFile = carefully_open_file(cryptFilename, 'wb+')
|
@@ -91,8 +89,8 @@ module CBC
|
|
91
89
|
plainFile.close unless plainFile.closed?
|
92
90
|
cryptFile.close unless cryptFile.closed?
|
93
91
|
end
|
94
|
-
|
95
|
-
|
92
|
+
|
93
|
+
|
96
94
|
def decrypt_file(cryptFilename, plainFilename)
|
97
95
|
cryptFile = carefully_open_file(cryptFilename, 'rb')
|
98
96
|
plainFile = carefully_open_file(plainFilename, 'wb+')
|
@@ -100,8 +98,8 @@ module CBC
|
|
100
98
|
cryptFile.close unless cryptFile.closed?
|
101
99
|
plainFile.close unless plainFile.closed?
|
102
100
|
end
|
103
|
-
|
104
|
-
|
101
|
+
|
102
|
+
|
105
103
|
def encrypt_string(plainText)
|
106
104
|
plainStream = StringIO.new(plainText)
|
107
105
|
cryptStream = StringIO.new('')
|
@@ -109,8 +107,8 @@ module CBC
|
|
109
107
|
cryptText = cryptStream.string
|
110
108
|
return(cryptText)
|
111
109
|
end
|
112
|
-
|
113
|
-
|
110
|
+
|
111
|
+
|
114
112
|
def decrypt_string(cryptText)
|
115
113
|
cryptStream = StringIO.new(cryptText)
|
116
114
|
plainStream = StringIO.new('')
|
@@ -118,6 +116,6 @@ module CBC
|
|
118
116
|
plainText = plainStream.string
|
119
117
|
return(plainText)
|
120
118
|
end
|
121
|
-
|
119
|
+
|
120
|
+
end
|
122
121
|
end
|
123
|
-
end
|
data/crypt/idea.rb
CHANGED
@@ -1,54 +1,54 @@
|
|
1
1
|
# idea.rb Richard Kernahan <kernighan_rich@rubyforge.org>
|
2
2
|
|
3
|
-
# IDEA (International Data Encryption Algorithm) by
|
3
|
+
# IDEA (International Data Encryption Algorithm) by
|
4
4
|
# Xuejia Lai and James Massey (1992). Refer to license info at end.
|
5
5
|
# Ported by Richard Kernahan 2005
|
6
6
|
|
7
7
|
module Crypt
|
8
8
|
class IDEA
|
9
|
-
|
9
|
+
|
10
10
|
require 'crypt/cbc'
|
11
11
|
include Crypt::CBC
|
12
12
|
|
13
13
|
require 'digest/md5'
|
14
|
-
|
14
|
+
|
15
15
|
ULONG = 0x100000000
|
16
16
|
USHORT = 0x10000
|
17
|
-
|
17
|
+
|
18
18
|
ENCRYPT = 0
|
19
19
|
DECRYPT = 1
|
20
|
-
|
21
|
-
|
20
|
+
|
21
|
+
|
22
22
|
def block_size
|
23
23
|
return(8)
|
24
24
|
end
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
|
27
27
|
def initialize(key128, mode)
|
28
28
|
# IDEA is subject to attack unless the key is sufficiently random, so we
|
29
29
|
# take an MD5 digest of a variable-length passphrase to ensure a solid key
|
30
|
-
if (key128.class == String)
|
31
|
-
digest = Digest::MD5.new(
|
30
|
+
if (key128.class == String)
|
31
|
+
digest = Digest::MD5.new().digest(key128)
|
32
32
|
key128 = digest.unpack('n'*8)
|
33
33
|
end
|
34
34
|
raise "Key must be 128 bits (8 words)" unless (key128.class == Array) && (key128.length == 8)
|
35
35
|
raise "Mode must be IDEA::ENCRYPT or IDEA::DECRYPT" unless ((mode == ENCRYPT) | (mode == DECRYPT))
|
36
36
|
if (mode == ENCRYPT)
|
37
37
|
@subkeys = generate_encryption_subkeys(key128)
|
38
|
-
else
|
38
|
+
else
|
39
39
|
@subkeys = generate_decryption_subkeys(key128)
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
43
|
-
|
42
|
+
|
43
|
+
|
44
44
|
def mul(a, b)
|
45
45
|
modulus = 0x10001
|
46
46
|
return((1 - b) % USHORT) if (a == 0)
|
47
47
|
return((1 - a) % USHORT) if (b == 0)
|
48
48
|
return((a * b) % modulus)
|
49
49
|
end
|
50
|
-
|
51
|
-
|
50
|
+
|
51
|
+
|
52
52
|
def mulInv(x)
|
53
53
|
modulus = 0x10001
|
54
54
|
x = x.to_i % USHORT
|
@@ -72,8 +72,8 @@ class IDEA
|
|
72
72
|
inv = (1 - t1) & 0xFFFF
|
73
73
|
return(inv)
|
74
74
|
end
|
75
|
-
|
76
|
-
|
75
|
+
|
76
|
+
|
77
77
|
def generate_encryption_subkeys(key)
|
78
78
|
encrypt_keys = []
|
79
79
|
encrypt_keys[0..7] = key.dup
|
@@ -84,8 +84,8 @@ class IDEA
|
|
84
84
|
}
|
85
85
|
return(encrypt_keys)
|
86
86
|
end
|
87
|
-
|
88
|
-
|
87
|
+
|
88
|
+
|
89
89
|
def generate_decryption_subkeys(key)
|
90
90
|
encrypt_keys = generate_encryption_subkeys(key)
|
91
91
|
decrypt_keys = []
|
@@ -108,8 +108,8 @@ class IDEA
|
|
108
108
|
}
|
109
109
|
return(decrypt_keys)
|
110
110
|
end
|
111
|
-
|
112
|
-
|
111
|
+
|
112
|
+
|
113
113
|
def crypt_pair(l, r)
|
114
114
|
word = [l, r].pack('NN').unpack('nnnn')
|
115
115
|
k = @subkeys[0..51]
|
@@ -137,15 +137,15 @@ class IDEA
|
|
137
137
|
twoLongs = result.pack('nnnn').unpack('NN')
|
138
138
|
return(twoLongs)
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
def encrypt_block(block)
|
142
142
|
xl, xr = block.unpack('NN')
|
143
143
|
xl, xr = crypt_pair(xl, xr)
|
144
144
|
encrypted = [xl, xr].pack('NN')
|
145
145
|
return(encrypted)
|
146
146
|
end
|
147
|
-
|
148
|
-
|
147
|
+
|
148
|
+
|
149
149
|
def decrypt_block(block)
|
150
150
|
xl, xr = block.unpack('NN')
|
151
151
|
xl, xr = crypt_pair(xl, xr)
|
@@ -167,27 +167,26 @@ end
|
|
167
167
|
# the algorithm for commercial purposes is thus subject to a license from Ascom
|
168
168
|
# Systec Ltd. of CH-5506 Maegenwil (Switzerland), being the patentee and sole
|
169
169
|
# owner of all rights, including the trademark IDEA.
|
170
|
-
#
|
170
|
+
#
|
171
171
|
# Commercial purposes shall mean any revenue generating purpose including but
|
172
172
|
# not limited to:
|
173
|
-
#
|
173
|
+
#
|
174
174
|
# i) Using the algorithm for company internal purposes (subject to a site
|
175
175
|
# license).
|
176
|
-
#
|
176
|
+
#
|
177
177
|
# ii) Incorporating the algorithm into any software and distributing such
|
178
178
|
# software and/or providing services relating thereto to others (subject to
|
179
179
|
# a product license).
|
180
|
-
#
|
180
|
+
#
|
181
181
|
# iii) Using a product containing the algorithm not covered by an IDEA license
|
182
182
|
# (subject to an end user license).
|
183
|
-
#
|
183
|
+
#
|
184
184
|
# All such end user license agreements are available exclusively from Ascom
|
185
185
|
# Systec Ltd and may be requested via the WWW at http://www.ascom.ch/systec or
|
186
186
|
# by email to idea@ascom.ch.
|
187
|
-
#
|
187
|
+
#
|
188
188
|
# Use other than for commercial purposes is strictly limited to non-revenue
|
189
189
|
# generating data transfer between private individuals. The use by government
|
190
190
|
# agencies, non-profit organizations, etc is considered as use for commercial
|
191
191
|
# purposes but may be subject to special conditions. Any misuse will be
|
192
192
|
# prosecuted.
|
193
|
-
|
data/crypt/noise.rb
CHANGED
@@ -17,7 +17,7 @@ module Noise
|
|
17
17
|
puts "is #{minimumNewLength} bytes which allows for no noise in the message."
|
18
18
|
puts "You should choose an obscured length of at least double the clear text"
|
19
19
|
puts "length, such as #{message.length / 8 * 32} bytes"
|
20
|
-
raise "Insufficient length for noisy message"
|
20
|
+
raise "Insufficient length for noisy message"
|
21
21
|
end
|
22
22
|
bitmap = []
|
23
23
|
usableNoisyMessageLength.times { bitmap << false }
|
@@ -32,8 +32,8 @@ module Noise
|
|
32
32
|
positionsSelected = positionsSelected.next
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
noisyMessage = ""
|
35
|
+
|
36
|
+
noisyMessage = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode
|
37
37
|
0.upto(bitmapSize-1) { |byte|
|
38
38
|
c = 0
|
39
39
|
0.upto(7) { |bit|
|
@@ -58,17 +58,17 @@ module Noise
|
|
58
58
|
}
|
59
59
|
return(noisyMessage)
|
60
60
|
end
|
61
|
-
|
62
|
-
|
61
|
+
|
62
|
+
|
63
63
|
def remove_noise
|
64
64
|
noisyMessage = self
|
65
65
|
bitmapSize = noisyMessage.length / 9
|
66
66
|
actualMessageLength = bitmapSize * 8
|
67
|
-
|
67
|
+
|
68
68
|
actualMessageStart = bitmapSize
|
69
69
|
actualMessageFinish = bitmapSize + actualMessageLength - 1
|
70
70
|
actualMessage = noisyMessage[actualMessageStart..actualMessageFinish]
|
71
|
-
|
71
|
+
|
72
72
|
bitmap = []
|
73
73
|
0.upto(bitmapSize - 1) { |byte|
|
74
74
|
c = noisyMessage[byte]
|
@@ -76,7 +76,7 @@ module Noise
|
|
76
76
|
bitmap[byte * 8 + bit] = (c[bit] == 1)
|
77
77
|
}
|
78
78
|
}
|
79
|
-
clearMessage = ""
|
79
|
+
clearMessage = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode
|
80
80
|
0.upto(actualMessageLength) { |pos|
|
81
81
|
meaningful = bitmap[pos]
|
82
82
|
if meaningful
|
@@ -85,10 +85,10 @@ module Noise
|
|
85
85
|
}
|
86
86
|
return(clearMessage)
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
92
|
class String
|
93
93
|
include Crypt::Noise
|
94
|
-
end
|
94
|
+
end
|