crypt 2.0 → 2.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 +4 -4
- data/{crypt → lib/crypt}/blowfish-tables.rb +59 -3
- data/{crypt → lib/crypt}/blowfish.rb +2 -3
- data/{crypt → lib/crypt}/cbc.rb +2 -2
- data/{crypt → lib/crypt}/gost.rb +3 -4
- data/{crypt → lib/crypt}/idea.rb +12 -54
- data/{crypt → lib/crypt}/noise.rb +2 -2
- data/{crypt → lib/crypt}/rijndael-tables.rb +2 -3
- data/{crypt → lib/crypt}/rijndael.rb +4 -5
- data/lib/crypt/stringxor.rb +17 -0
- data/specs/blowfish.rb +80 -0
- data/specs/gost.rb +48 -0
- data/specs/idea.rb +156 -0
- data/specs/rijndael.rb +58 -0
- metadata +21 -23
- data/crypt/stringxor.rb +0 -27
- data/test/break-idea.rb +0 -61
- data/test/devServer.rb +0 -16
- data/test/test-blowfish.rb +0 -90
- data/test/test-gost.rb +0 -77
- data/test/test-idea.rb +0 -79
- data/test/test-rijndael.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c26c671cabb4969a940b582444ad370d623e18b2
|
4
|
+
data.tar.gz: db5d9d98b3519d5b7ae97098db35946ef612f192
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 042e0eaa49184aff6932e6697ec475dec5592d1a55c9c34444e4ebabbc5bcbdacb0ad6b07cb2cad4b2e16490a0ede0955b143c815e4e43b81d78e6d93ddae609
|
7
|
+
data.tar.gz: 9250d375de4633729a07357d5489497cd92d0f72994882f3833e01ab2aff8dd0e64942a6a918fae9b180cbfca753348e9484529c8092dcc63564276c84f95f09
|
@@ -1,5 +1,61 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
#The Crypt library is a pure-ruby implementation of a number of popular encryption algorithms.
|
2
|
+
#Block cyphers currently available include Blowfish, GOST, IDEA, and Rijndael (AES).
|
3
|
+
#Cypher Block Chaining (CBC) has been implemented.
|
4
|
+
#
|
5
|
+
#Crypt is written entirely in ruby so deployment is simple - no platform concerns,
|
6
|
+
#no library dependencies, nothing to compile.
|
7
|
+
#
|
8
|
+
#Performance is what you would expect from a pure-ruby implementation: it is adequate for shorter messages
|
9
|
+
#but I wouldn't try to encrypt my whole disk with it. If performance is critical then you might want to try
|
10
|
+
#ezcrypto's (http://ezcrypto.rubyforge.org) interface to OpenSSL.
|
11
|
+
#
|
12
|
+
#v.2.2.0 released 23 Sep 2015 fixes a defect in IDEA and replaces tests with specs.
|
13
|
+
#
|
14
|
+
# require 'crypt/blowfish'
|
15
|
+
# blowfish = Crypt::Blowfish.new("A key up to 56 bytes long")
|
16
|
+
# plainBlock = "ABCD1234"
|
17
|
+
# encryptedBlock = blowfish.encrypt_block(plainBlock)
|
18
|
+
# decryptedBlock = blowfish.decrypt_block(encryptedBlock)
|
19
|
+
# string = "This is a string which is not a multiple of 8 characters long"
|
20
|
+
# encryptedString = bf.encrypt_string(string)
|
21
|
+
# decryptedString = bf.decrypt_string(encryptedString)
|
22
|
+
# bf.encrypt_file('plain.txt', 'crypt.txt')
|
23
|
+
# bf.decrypt_file('crypt.txt', 'decrypt.txt')
|
24
|
+
#
|
25
|
+
# require 'crypt/gost'
|
26
|
+
# # a key shorter than 32 bytes will be padded out with zeroes
|
27
|
+
# gost = Crypt::Gost.new("This is a contrived 32 byte key!")
|
28
|
+
# plainBlock = "ABCD1234"
|
29
|
+
# encryptedBlock = gost.encrypt_block(plainBlock)
|
30
|
+
# decryptedBlock = gost.decrypt_block(encryptedBlock)
|
31
|
+
#
|
32
|
+
# require 'crypt/idea'
|
33
|
+
# idea = Crypt::IDEA.new("A key up to 56 bytes long")
|
34
|
+
# plainBlock = "ABCD1234"
|
35
|
+
# encryptedBlock = idea.encrypt_block(plainBlock)
|
36
|
+
# decryptedBlock = idea.decrypt_block(encryptedBlock)
|
37
|
+
#
|
38
|
+
# require 'crypt/rijndael'
|
39
|
+
# rijndael = Crypt::Rijndael.new("A key 16, 24, or 32 bytes length")
|
40
|
+
# plainBlock = "ABCDEFGH12345678"
|
41
|
+
# encryptedBlock = rijndael.encrypt_block(plainBlock)
|
42
|
+
# decryptedBlock = rijndael.decrypt_block(encryptedBlock)
|
43
|
+
#
|
44
|
+
#Cipher-block chaining (CBC) is supported for each algorithm:
|
45
|
+
#
|
46
|
+
# blowfish = Crypt::Blowfish.new("A sample key better than this one")
|
47
|
+
# blowfish.encrypt_file('plain.txt', 'crypt.txt')
|
48
|
+
# blowfish.decrypt_file('crypt.txt', 'plain.txt')
|
49
|
+
#
|
50
|
+
#You can also read from a plain text stream,
|
51
|
+
#encrypt and write to an encrypted output stream, or treat a string as a stream:
|
52
|
+
#
|
53
|
+
# f = File.new('plain.txt', 'r')
|
54
|
+
# g = TCPSocket.new('encrypted.example.com', 2222)
|
55
|
+
# blowfish.encrypt_stream(f, g)
|
56
|
+
#
|
57
|
+
# plainText = "This is plain text."
|
58
|
+
# encrypted = blowfish.encrypt_string(plainText)
|
3
59
|
module Crypt
|
4
60
|
module BlowfishTables
|
5
61
|
|
@@ -187,4 +243,4 @@ module BlowfishTables
|
|
187
243
|
|
188
244
|
|
189
245
|
end
|
190
|
-
end
|
246
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
|
1
|
+
module Crypt
|
2
|
+
# blowfish.rb Richard Kernahan
|
2
3
|
#
|
3
4
|
# Blowfish algorithm by Bruce Schneider
|
4
5
|
# Ported by Richard Kernahan from the reference C code
|
5
|
-
|
6
|
-
module Crypt
|
7
6
|
class Blowfish
|
8
7
|
|
9
8
|
require 'crypt/cbc'
|
data/{crypt → lib/crypt}/cbc.rb
RENAMED
data/{crypt → lib/crypt}/gost.rb
RENAMED
@@ -1,9 +1,8 @@
|
|
1
|
+
module Crypt
|
1
2
|
# gost.rb
|
2
|
-
# Adapted by Richard Kernahan
|
3
|
+
# Adapted by Richard Kernahan
|
3
4
|
# from C++ code written by Wei Dai
|
4
5
|
# of the Crypto++ project http://www.eskimo.com/~weidai/cryptlib.html
|
5
|
-
|
6
|
-
module Crypt
|
7
6
|
class Gost
|
8
7
|
|
9
8
|
require 'crypt/cbc'
|
@@ -137,4 +136,4 @@ class Gost
|
|
137
136
|
|
138
137
|
|
139
138
|
end
|
140
|
-
end
|
139
|
+
end
|
data/{crypt → lib/crypt}/idea.rb
RENAMED
@@ -1,10 +1,9 @@
|
|
1
|
-
|
1
|
+
module Crypt
|
2
|
+
# idea.rb Richard Kernahan
|
2
3
|
|
3
4
|
# IDEA (International Data Encryption Algorithm) by
|
4
|
-
# Xuejia Lai and James Massey (1992).
|
5
|
-
# Ported by Richard Kernahan 2005
|
5
|
+
# Xuejia Lai and James Massey (1992). Ported by Richard Kernahan 2005
|
6
6
|
|
7
|
-
module Crypt
|
8
7
|
class IDEA
|
9
8
|
|
10
9
|
require 'crypt/cbc'
|
@@ -12,24 +11,23 @@ class IDEA
|
|
12
11
|
|
13
12
|
require 'digest/md5'
|
14
13
|
|
15
|
-
ULONG = 0x100000000
|
16
14
|
USHORT = 0x10000
|
17
15
|
|
18
16
|
ENCRYPT = 0
|
19
17
|
DECRYPT = 1
|
20
|
-
|
18
|
+
|
19
|
+
attr_accessor(:subkeys)
|
21
20
|
|
22
21
|
def block_size
|
23
22
|
return(8)
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
25
|
def initialize(key128, mode)
|
28
26
|
# IDEA is subject to attack unless the key is sufficiently random, so we
|
29
27
|
# take an MD5 digest of a variable-length passphrase to ensure a solid key
|
30
28
|
if (key128.class == String)
|
31
|
-
digest = Digest::MD5.new().digest(key128)
|
32
|
-
key128 = digest.unpack('
|
29
|
+
digest = Digest::MD5.new().digest(key128.b).b()
|
30
|
+
key128 = digest.unpack('n8')
|
33
31
|
end
|
34
32
|
raise "Key must be 128 bits (8 words)" unless (key128.class == Array) && (key128.length == 8)
|
35
33
|
raise "Mode must be IDEA::ENCRYPT or IDEA::DECRYPT" unless ((mode == ENCRYPT) | (mode == DECRYPT))
|
@@ -39,21 +37,19 @@ class IDEA
|
|
39
37
|
@subkeys = generate_decryption_subkeys(key128)
|
40
38
|
end
|
41
39
|
end
|
42
|
-
|
43
|
-
|
40
|
+
|
44
41
|
def mul(a, b)
|
45
42
|
modulus = 0x10001
|
46
43
|
return((1 - b) % USHORT) if (a == 0)
|
47
44
|
return((1 - a) % USHORT) if (b == 0)
|
48
|
-
return((a * b) % modulus)
|
45
|
+
return((a * b) % modulus % USHORT) # fixed with % USHORT
|
49
46
|
end
|
50
47
|
|
51
|
-
|
52
48
|
def mulInv(x)
|
53
49
|
modulus = 0x10001
|
54
|
-
x = x.to_i %
|
50
|
+
x = x.to_i % 0x10000
|
55
51
|
return(x) if (x <= 1)
|
56
|
-
t1 =
|
52
|
+
t1 = modulus / x
|
57
53
|
y = modulus % x
|
58
54
|
if (y == 1)
|
59
55
|
inv = (1 - t1) & 0xFFFF
|
@@ -73,7 +69,6 @@ class IDEA
|
|
73
69
|
return(inv)
|
74
70
|
end
|
75
71
|
|
76
|
-
|
77
72
|
def generate_encryption_subkeys(key)
|
78
73
|
encrypt_keys = []
|
79
74
|
encrypt_keys[0..7] = key.dup
|
@@ -85,7 +80,6 @@ class IDEA
|
|
85
80
|
return(encrypt_keys)
|
86
81
|
end
|
87
82
|
|
88
|
-
|
89
83
|
def generate_decryption_subkeys(key)
|
90
84
|
encrypt_keys = generate_encryption_subkeys(key)
|
91
85
|
decrypt_keys = []
|
@@ -97,7 +91,7 @@ class IDEA
|
|
97
91
|
decrypt_keys[i+4] = encrypt_keys.shift % USHORT
|
98
92
|
decrypt_keys[i+5] = encrypt_keys.shift % USHORT
|
99
93
|
decrypt_keys[i] = mulInv(encrypt_keys.shift)
|
100
|
-
if (i ==0)
|
94
|
+
if (i == 0)
|
101
95
|
decrypt_keys[1] = (-encrypt_keys.shift) % USHORT
|
102
96
|
decrypt_keys[2] = (-encrypt_keys.shift) % USHORT
|
103
97
|
else
|
@@ -109,7 +103,6 @@ class IDEA
|
|
109
103
|
return(decrypt_keys)
|
110
104
|
end
|
111
105
|
|
112
|
-
|
113
106
|
def crypt_pair(l, r)
|
114
107
|
word = [l, r].pack('NN').unpack('nnnn')
|
115
108
|
k = @subkeys[0..51]
|
@@ -145,7 +138,6 @@ class IDEA
|
|
145
138
|
return(encrypted)
|
146
139
|
end
|
147
140
|
|
148
|
-
|
149
141
|
def decrypt_block(block)
|
150
142
|
xl, xr = block.unpack('NN')
|
151
143
|
xl, xr = crypt_pair(xl, xr)
|
@@ -153,40 +145,6 @@ class IDEA
|
|
153
145
|
return(decrypted)
|
154
146
|
end
|
155
147
|
|
156
|
-
|
157
148
|
end
|
158
149
|
end
|
159
150
|
|
160
|
-
# LICENSE INFORMATION
|
161
|
-
#
|
162
|
-
# This software product contains the IDEA algorithm as described and claimed in
|
163
|
-
# US patent 5,214,703, EPO patent 0482154 (covering Austria, France, Germany,
|
164
|
-
# Italy, the Netherlands, Spain, Sweden, Switzerland, and the UK), and Japanese
|
165
|
-
# patent application 508119/1991, "Device for the conversion of a digital block
|
166
|
-
# and use of same" (hereinafter referred to as "the algorithm"). Any use of
|
167
|
-
# the algorithm for commercial purposes is thus subject to a license from Ascom
|
168
|
-
# Systec Ltd. of CH-5506 Maegenwil (Switzerland), being the patentee and sole
|
169
|
-
# owner of all rights, including the trademark IDEA.
|
170
|
-
#
|
171
|
-
# Commercial purposes shall mean any revenue generating purpose including but
|
172
|
-
# not limited to:
|
173
|
-
#
|
174
|
-
# i) Using the algorithm for company internal purposes (subject to a site
|
175
|
-
# license).
|
176
|
-
#
|
177
|
-
# ii) Incorporating the algorithm into any software and distributing such
|
178
|
-
# software and/or providing services relating thereto to others (subject to
|
179
|
-
# a product license).
|
180
|
-
#
|
181
|
-
# iii) Using a product containing the algorithm not covered by an IDEA license
|
182
|
-
# (subject to an end user license).
|
183
|
-
#
|
184
|
-
# All such end user license agreements are available exclusively from Ascom
|
185
|
-
# Systec Ltd and may be requested via the WWW at http://www.ascom.ch/systec or
|
186
|
-
# by email to idea@ascom.ch.
|
187
|
-
#
|
188
|
-
# Use other than for commercial purposes is strictly limited to non-revenue
|
189
|
-
# generating data transfer between private individuals. The use by government
|
190
|
-
# agencies, non-profit organizations, etc is considered as use for commercial
|
191
|
-
# purposes but may be subject to special conditions. Any misuse will be
|
192
|
-
# prosecuted.
|
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
module Crypt
|
2
|
+
# crypt/noise.rb Richard Kernahan
|
2
3
|
|
3
4
|
# add_noise - take a message and intersperse noise to make a new noisy message of given byte-length
|
4
5
|
# remove_noise - take a noisy message and extract the message
|
5
6
|
|
6
|
-
module Crypt
|
7
7
|
module Noise
|
8
8
|
|
9
9
|
def add_noise(newLength)
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require 'crypt/cbc'
|
2
|
+
# rijndael.rb Richard Kernahan
|
2
3
|
|
3
4
|
# Adapted from the reference C implementation:
|
4
5
|
# rijndael-alg-ref.c v2.2 March 2002
|
@@ -6,16 +7,14 @@
|
|
6
7
|
# authors: Paulo Barreto and Vincent Rijmen
|
7
8
|
# This code is placed in the public domain.
|
8
9
|
|
10
|
+
require 'crypt/rijndael-tables'
|
11
|
+
|
9
12
|
module Crypt
|
10
13
|
class Rijndael
|
11
14
|
|
12
|
-
require 'crypt/cbc'
|
13
15
|
include Crypt::CBC
|
14
|
-
|
15
|
-
require 'crypt/rijndael-tables'
|
16
16
|
include Crypt::RijndaelTables
|
17
17
|
|
18
|
-
|
19
18
|
def initialize(userKey, keyBits = 256, blockBits = 128)
|
20
19
|
case keyBits
|
21
20
|
when 128
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def ^(aString)
|
4
|
+
a = self.b.unpack('C'*(self.length))
|
5
|
+
b = aString.b.unpack('C'*(aString.length))
|
6
|
+
if (b.length < a.length)
|
7
|
+
(a.length - b.length).times { b << 0 }
|
8
|
+
end
|
9
|
+
xor = "".b()
|
10
|
+
0.upto(a.length-1) { |pos|
|
11
|
+
x = a[pos] ^ b[pos]
|
12
|
+
xor << x.chr()
|
13
|
+
}
|
14
|
+
return(xor)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/specs/blowfish.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'crypt/blowfish'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe "Crypt::Blowfish" do
|
5
|
+
|
6
|
+
it "has a blocksize of 8" do
|
7
|
+
bf = Crypt::Blowfish.new("Who is John Galt?") # Schneier's test key
|
8
|
+
expect(bf.block_size).to eql(8)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "requires a key of 1-56 bytes" do
|
12
|
+
expect {
|
13
|
+
b0 = Crypt::Blowfish.new("")
|
14
|
+
}.to raise_error(RuntimeError)
|
15
|
+
expect {
|
16
|
+
b1 = Crypt::Blowfish.new("1")
|
17
|
+
}.not_to raise_error()
|
18
|
+
expect {
|
19
|
+
b56 = Crypt::Blowfish.new("1"*56)
|
20
|
+
}.not_to raise_error()
|
21
|
+
expect {
|
22
|
+
b57 = Crypt::Blowfish.new("1"*57)
|
23
|
+
}.to raise_error(RuntimeError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "encrypts and decrypts 4-byte pairs" do
|
27
|
+
bf = Crypt::Blowfish.new("Who is John Galt?")
|
28
|
+
orig_l, orig_r = [0xfedcba98, 0x76543210]
|
29
|
+
l, r = bf.encrypt_pair(orig_l, orig_r)
|
30
|
+
expect(l).to eql(0xcc91732b)
|
31
|
+
expect(r).to eql(0x8022f684)
|
32
|
+
l, r = bf.decrypt_pair(l, r)
|
33
|
+
expect(l).to eql(orig_l)
|
34
|
+
expect(r).to eql(orig_r)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "encrypts and decrypts 8-byte blocks" do
|
38
|
+
bf = Crypt::Blowfish.new("Who is John Galt?")
|
39
|
+
block = "8 byte\u00cd" # unicode string of 8 bytes
|
40
|
+
encryptedBlock = bf.encrypt_block(block)
|
41
|
+
expect(encryptedBlock).to eql("\xC4G\xD3\xFD7\xF4\x1E\xD0".b())
|
42
|
+
decryptedBlock = bf.decrypt_block(encryptedBlock)
|
43
|
+
expect(decryptedBlock).to eql(block)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "encrypts and decrypts strings" do
|
47
|
+
length = 30 + rand(26)
|
48
|
+
userkey = ""
|
49
|
+
length.times { userkey << rand(256).chr }
|
50
|
+
bf = Crypt::Blowfish.new(userkey)
|
51
|
+
string = "This is a string which is not a multiple of 8 characters long"
|
52
|
+
encryptedString = bf.encrypt_string(string)
|
53
|
+
decryptedString = bf.decrypt_string(encryptedString)
|
54
|
+
expect(decryptedString).to eql(string)
|
55
|
+
secondstring = "This is another string to check repetitive use."
|
56
|
+
encryptedString = bf.encrypt_string(secondstring)
|
57
|
+
decryptedString = bf.decrypt_string(encryptedString)
|
58
|
+
expect(decryptedString).to eql(secondstring)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "encrypts and decrypts a file" do
|
62
|
+
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
63
|
+
plainFile = File.new('plain.txt', 'wb+')
|
64
|
+
plainFile.puts(plainText)
|
65
|
+
plainFile.close()
|
66
|
+
bf = Crypt::Blowfish.new("Who is John Galt?")
|
67
|
+
bf.encrypt_file('plain.txt', 'crypt.txt')
|
68
|
+
bf.decrypt_file('crypt.txt', 'decrypt.txt')
|
69
|
+
decryptFile = File.new('decrypt.txt', 'rb')
|
70
|
+
decryptText = decryptFile.readlines().join('').chomp()
|
71
|
+
decryptFile.close()
|
72
|
+
expect(decryptText).to eql(plainText)
|
73
|
+
FileUtils.rm('plain.txt')
|
74
|
+
FileUtils.rm('crypt.txt')
|
75
|
+
FileUtils.rm('decrypt.txt')
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
|
data/specs/gost.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'crypt/gost'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe "Crypt::Gost" do
|
5
|
+
|
6
|
+
it "has a blocksize of 8" do
|
7
|
+
gost = Crypt::Gost.new("Whatever happened to Yuri Gagarin?")
|
8
|
+
expect(gost.block_size).to eql(8)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "encrypts and decrypts 8-byte blocks" do
|
12
|
+
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
13
|
+
block = "norandom"
|
14
|
+
encryptedBlock = gost.encrypt_block(block)
|
15
|
+
expect(encryptedBlock).to eql(".Vy\xFF\x05\e3`".b())
|
16
|
+
decryptedBlock = gost.decrypt_block(encryptedBlock)
|
17
|
+
expect(decryptedBlock).to eql(block)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "encrypts and decrypts strings" do
|
21
|
+
length = 25 + rand(12)
|
22
|
+
userkey = ""
|
23
|
+
length.times { userkey << rand(256).chr }
|
24
|
+
gost = Crypt::Gost.new(userkey)
|
25
|
+
string = "This is a string which is not a multiple of 8 characters long"
|
26
|
+
encryptedString = gost.encrypt_string(string)
|
27
|
+
decryptedString = gost.decrypt_string(encryptedString)
|
28
|
+
expect(decryptedString).to eql(string)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "encrypts and decrypts a file" do
|
32
|
+
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
33
|
+
plainFile = File.new('plain.txt', 'wb+')
|
34
|
+
plainFile.puts(plainText)
|
35
|
+
plainFile.close()
|
36
|
+
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
37
|
+
gost.encrypt_file('plain.txt', 'crypt.txt')
|
38
|
+
gost.decrypt_file('crypt.txt', 'decrypt.txt')
|
39
|
+
decryptFile = File.new('decrypt.txt', 'rb')
|
40
|
+
decryptText = decryptFile.readlines().join('').chomp()
|
41
|
+
decryptFile.close()
|
42
|
+
expect(decryptText).to eql(plainText)
|
43
|
+
FileUtils.rm('plain.txt')
|
44
|
+
FileUtils.rm('crypt.txt')
|
45
|
+
FileUtils.rm('decrypt.txt')
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/specs/idea.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'crypt/idea'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe "Crypt::IDEA" do
|
5
|
+
|
6
|
+
it "encrypts and decrypts 4-byte pairs" do
|
7
|
+
enc = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::ENCRYPT)
|
8
|
+
dec = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::DECRYPT)
|
9
|
+
origL = 0x385a41f2
|
10
|
+
origR = 0xe03e5930
|
11
|
+
cl, cr = enc.crypt_pair(origL, origR)
|
12
|
+
dl, dr = dec.crypt_pair(cl, cr)
|
13
|
+
expect(dl).to eql(origL)
|
14
|
+
expect(dr).to eql(origR)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "encrypts and decrypts 8-byte blocks" do
|
18
|
+
enc = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::ENCRYPT)
|
19
|
+
dec = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::DECRYPT)
|
20
|
+
block = "norandom"
|
21
|
+
encryptedBlock = enc.encrypt_block(block)
|
22
|
+
expect(encryptedBlock).to eql("\xC2lzEU\x81\e_".b())
|
23
|
+
decryptedBlock = dec.decrypt_block(encryptedBlock)
|
24
|
+
expect(decryptedBlock).to eql(block)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "encrypts and decrypts strings" do
|
28
|
+
enc = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::ENCRYPT)
|
29
|
+
dec = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::DECRYPT)
|
30
|
+
string = "This is a string which is not a multiple of 8 characters long"
|
31
|
+
encryptedString = enc.encrypt_string(string)
|
32
|
+
decryptedString = dec.decrypt_string(encryptedString)
|
33
|
+
expect(decryptedString).to eql(string)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "encrypts and decrypts a file" do
|
37
|
+
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
38
|
+
plainFile = File.new('plain.txt', 'wb+')
|
39
|
+
plainFile.puts(plainText)
|
40
|
+
plainFile.close()
|
41
|
+
enc = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::ENCRYPT)
|
42
|
+
dec = Crypt::IDEA.new("Nothing can stop an idea whose time has come", Crypt::IDEA::DECRYPT)
|
43
|
+
enc.encrypt_file('plain.txt', 'crypt.txt')
|
44
|
+
dec.decrypt_file('crypt.txt', 'decrypt.txt')
|
45
|
+
decryptFile = File.new('decrypt.txt', 'rb')
|
46
|
+
decryptText = decryptFile.readlines().join('').chomp()
|
47
|
+
decryptFile.close()
|
48
|
+
expect(decryptText).to eql(plainText)
|
49
|
+
FileUtils.rm('plain.txt')
|
50
|
+
FileUtils.rm('crypt.txt')
|
51
|
+
FileUtils.rm('decrypt.txt')
|
52
|
+
end
|
53
|
+
|
54
|
+
def h(s)
|
55
|
+
[s].pack("H*")
|
56
|
+
end
|
57
|
+
|
58
|
+
def n8(s)
|
59
|
+
h(s).unpack("n8")
|
60
|
+
end
|
61
|
+
|
62
|
+
def conform(key, plain, cipher)
|
63
|
+
enc = Crypt::IDEA.new("", Crypt::IDEA::ENCRYPT)
|
64
|
+
enc.subkeys = enc.generate_encryption_subkeys(key)
|
65
|
+
dec = Crypt::IDEA.new("", Crypt::IDEA::ENCRYPT)
|
66
|
+
dec.subkeys = dec.generate_decryption_subkeys(key)
|
67
|
+
encryptedBlock = enc.encrypt_block(plain)
|
68
|
+
expect(encryptedBlock).to eql(cipher.b())
|
69
|
+
decryptedBlock = dec.decrypt_block(encryptedBlock)
|
70
|
+
expect(decryptedBlock).to eql(plain)
|
71
|
+
end
|
72
|
+
|
73
|
+
def conform_dec(key, cipher, plain)
|
74
|
+
dec = Crypt::IDEA.new("", Crypt::IDEA::ENCRYPT)
|
75
|
+
dec.subkeys = dec.generate_decryption_subkeys(key)
|
76
|
+
decryptedBlock = dec.decrypt_block(cipher)
|
77
|
+
expect(decryptedBlock).to eql(plain)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "conforms to enceryption test vectors" do
|
81
|
+
conform([0x8000,0,0,0,0,0,0,0], h("0000000000000000"), h("B1F5F7F87901370F"))
|
82
|
+
conform([0x4000,0,0,0,0,0,0,0], h("0000000000000000"), h("B3927DFFB6358626"))
|
83
|
+
conform([0x2000,0,0,0,0,0,0,0], h("0000000000000000"), h("E987E0029FB99785"))
|
84
|
+
conform([0x1000,0,0,0,0,0,0,0], h("0000000000000000"), h("754A03CE08DB7DAA"))
|
85
|
+
conform([0x0800,0,0,0,0,0,0,0], h("0000000000000000"), h("F015F9FB0CFC7E1C"))
|
86
|
+
conform([0x0400,0,0,0,0,0,0,0], h("0000000000000000"), h("69C9FE6007B8FCDF"))
|
87
|
+
conform([0x0200,0,0,0,0,0,0,0], h("0000000000000000"), h("8DA7BC0E63B40DD0"))
|
88
|
+
conform([0x0100,0,0,0,0,0,0,0], h("0000000000000000"), h("2C49BF7DE28C666B"))
|
89
|
+
conform([ 0x80,0,0,0,0,0,0,0], h("0000000000000000"), h("9A4717E8F935712B"))
|
90
|
+
conform([0,0x8000,0,0,0,0,0,0], h("0000000000000000"), h("95A96731978C1B9A"))
|
91
|
+
conform([0,0,0x8000,0,0,0,0,0], h("0000000000000000"), h("398BD9A59E9F5DDB"))
|
92
|
+
conform([0,0,0,0x8000,0,0,0,0], h("0000000000000000"), h("AC1D8708AF0A37EE"))
|
93
|
+
conform([0,0,0,0,0x8000,0,0,0], h("0000000000000000"), h("FAE3FA7B8DB08800"))
|
94
|
+
conform([0,0,0,0,0,0x8000,0,0], h("0000000000000000"), h("B5803F82C0633F01"))
|
95
|
+
conform([0,0,0,0,0, 0x10,0,0], h("0000000000000000"), h("9E25090B7D4EF24E"))
|
96
|
+
conform([0,0,0,0,0, 0x8,0,0], h("0000000000000000"), h("EF62C1109F374AA8"))
|
97
|
+
conform([0,0,0,0,0, 0x2,0,0], h("0000000000000000"), h("5F0CCFE5EB0F19A8"))
|
98
|
+
conform([0xffff,0xffff,0xffff,0xffff,0xffff,0x1,0x000f,0xffff], h("0000000000000000"), h("2E4329C12455430B"))
|
99
|
+
# had problems with bits 95 to 108 inclusive, fixed by final % USHORT on mul()
|
100
|
+
conform([0,0,0,0,0, 0x1,0,0], h("0000000000000000"), h("FCC40014010D617C"))
|
101
|
+
conform([0,0,0,0,0,0,0x8000,0], h("0000000000000000"), h("705D780834A498DA"))
|
102
|
+
conform([0,0,0,0,0,0,0x4000,0], h("0000000000000000"), h("9BCA7BF025B38A68"))
|
103
|
+
conform([0,0,0,0,0,0,0x2000,0], h("0000000000000000"), h("5CF67D0181CB01C1"))
|
104
|
+
conform([0,0,0,0,0,0,0x1000,0], h("0000000000000000"), h("ECDE3D81820381C1"))
|
105
|
+
conform([0,0,0,0,0,0, 0x80,0], h("0000000000000000"), h("C781050DC4110220"))
|
106
|
+
conform([0,0,0,0,0,0, 0x40,0], h("0000000000000000"), h("6DFD0287EC4C0110"))
|
107
|
+
conform([0,0,0,0,0,0, 0x20,0], h("0000000000000000"), h("3B8A017EFB61800E"))
|
108
|
+
conform([0,0,0,0,0,0, 0x10,0], h("0000000000000000"), h("A08F7F81FF627FC0"))
|
109
|
+
conform([0,0,0,0,0,0, 0x8,0], h("0000000000000000"), h("00503FC1AFB93FE0"))
|
110
|
+
conform([0,0,0,0,0,0, 0x1,0], h("0000000000000000"), h("46D371477F33B152"))
|
111
|
+
conform([0,0,0,0,0,0,0,0x8000], h("0000000000000000"), h("BE67AC7DA294CA7C"))
|
112
|
+
conform([0,0,0,0,0,0,0,0], h("8000000000000000"), h("8001000180008000"))
|
113
|
+
conform([0,0,0,0,0,0,0,0], h("0080000000000000"), h("9181E3014C80C980"))
|
114
|
+
conform([0,0,0,0,0,0,0,0], h("0000800000000000"), h("0001800180008000"))
|
115
|
+
conform([0,0,0,0,0,0,0,0], h("0000000200000000"), h("FF49003BFF26FFAA"))
|
116
|
+
conform([0,0,0,0,0,0,0,0], h("0000000004000000"), h("100100014C00E000"))
|
117
|
+
conform([0,0,0,0,0,0,0,0], h("0000000000040000"), h("01110001FE4C00E0"))
|
118
|
+
conform([0,0,0,0,0,0,0,0], h("0000000000001000"), h("8001C001E0009000"))
|
119
|
+
conform([0,0,0,0,0,0,0,0], h("0000000000000100"), h("C8012C018E009900"))
|
120
|
+
conform([0,0,0,0,0,0,0,0], h("0000000000000040"), h("32010B012380E640"))
|
121
|
+
conform([0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101], h("0101010101010101"), h("E3F8AFF7A3795615"))
|
122
|
+
conform([0x7777,0x7777,0x7777,0x7777,0x7777,0x7777,0x7777,0x7777], h("7777777777777777"), h("D2E486D93304B9B6"))
|
123
|
+
conform([0xF7F7,0xF7F7,0xF7F7,0xF7F7,0xF7F7,0xF7F7,0xF7F7,0xF7F7], h("F7F7F7F7F7F7F7F7"), h("8E13C368F53E55AF"))
|
124
|
+
conform([1,0x203,0x405,0x607,0x809,0xa0b,0xc0d,0xe0f], h("0011223344556677"), h("F526AB9A62C0D258"))
|
125
|
+
end
|
126
|
+
|
127
|
+
it "conforms to decryption test vectors" do
|
128
|
+
conform_dec(n8("80000000000000000000000000000000"), h("0000000000000000"), h("78071EE87F0130E8"))
|
129
|
+
conform_dec(n8("00008000000000000000000000000000"), h("0000000000000000"), h("14D47C44835EEB99"))
|
130
|
+
conform_dec(n8("00000000800000000000000000000000"), h("0000000000000000"), h("CEA444C8CE44C2C2"))
|
131
|
+
conform_dec(n8("00000000000000000080000000000000"), h("0000000000000000"), h("6A9EF2F77DE21D8E"))
|
132
|
+
conform_dec(n8("00000000000000000000000800000000"), h("0000000000000000"), h("E698BE39AEA13C79"))
|
133
|
+
conform_dec(n8("00000000000000000000000000400000"), h("0000000000000000"), h("0579E00B945ED0B2"))
|
134
|
+
conform_dec(n8("00000000000000000000000000080000"), h("0000000000000000"), h("F0903DB58BEFF8CF"))
|
135
|
+
conform_dec(n8("00000000000000000000000000000040"), h("0000000000000000"), h("F75986F389F08110"))
|
136
|
+
conform_dec(n8("00000000000000000000000000000000"), h("8000000000000000"), h("8001000180008000"))
|
137
|
+
conform_dec(n8("00000000000000000000000000000000"), h("0002000000000000"), h("FE47FF8D0132FF26"))
|
138
|
+
conform_dec(n8("00000000000000000000000000000000"), h("0000000000200000"), h("08810001F2600700"))
|
139
|
+
conform_dec(n8("00000000000000000000000000000000"), h("0000000000000400"), h("2001B00138006400"))
|
140
|
+
conform_dec(n8("11111111111111111111111111111111"), h("1111111111111111"), h("3A1D3B4DB127C8B7"))
|
141
|
+
conform_dec(n8("52525252525252525252525252525252"), h("5252525252525252"), h("B255918917D30DB6"))
|
142
|
+
conform_dec(n8("66666666666666666666666666666666"), h("6666666666666666"), h("C9248B00868D8651"))
|
143
|
+
conform_dec(n8("ABABABABABABABABABABABABABABABAB"), h("ABABABABABABABAB"), h("5A4C4870F25A207F"))
|
144
|
+
conform_dec(n8("000102030405060708090A0B0C0D0E0F"), h("0011223344556677"), h("DB2D4A92AA68273F"))
|
145
|
+
conform_dec(n8("2BD6459F82C5B300952C49104881FF48"), h("EA024714AD5C4D84"), h("F129A6601EF62A47"))
|
146
|
+
end
|
147
|
+
|
148
|
+
it "calculates multiplicative inverses" do
|
149
|
+
idea = Crypt::IDEA.new("", Crypt::IDEA::ENCRYPT)
|
150
|
+
expect(idea.mulInv(0)).to eql(0)
|
151
|
+
(1..0xffff).each { |i|
|
152
|
+
expect(i * idea.mulInv(i) % 0x10001).to eql(1)
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
data/specs/rijndael.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'crypt/rijndael'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe "Crypt::Rijndael" do
|
5
|
+
|
6
|
+
it "has a blocksize of 128, 192, or 256 bits" do
|
7
|
+
expect {
|
8
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 64)
|
9
|
+
}.to raise_error(RuntimeError)
|
10
|
+
expect {
|
11
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 64)
|
12
|
+
}.to raise_error(RuntimeError)
|
13
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 256)
|
14
|
+
expect(rijndael.block_size).to eql(32)
|
15
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 256, 128)
|
16
|
+
expect(rijndael.block_size).to eql(16)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "encrypts and decrypts 8-byte blocks" do
|
20
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 128)
|
21
|
+
block = "This block \u00cd 16" # unicode string of 16 bytes
|
22
|
+
encryptedBlock = rijndael.encrypt_block(block)
|
23
|
+
expect(encryptedBlock).to eql("\x8E\x88\x03\xB8> PnwR)\x93\x1A\xC9:\xC4".b())
|
24
|
+
decryptedBlock = rijndael.decrypt_block(encryptedBlock)
|
25
|
+
expect(decryptedBlock).to eql(block)
|
26
|
+
# attempt to encrypt with wrong block size
|
27
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 256)
|
28
|
+
expect {
|
29
|
+
encryptedBlock = rijndael.encrypt_block(block)
|
30
|
+
}.to raise_error(RuntimeError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "encrypts and decrypts strings" do
|
34
|
+
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?")
|
35
|
+
string = "This is a string which is not a multiple of 8 characters long"
|
36
|
+
encryptedString = rijndael.encrypt_string(string)
|
37
|
+
decryptedString = rijndael.decrypt_string(encryptedString)
|
38
|
+
expect(decryptedString).to eql(string)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "encrypts and decrypts a file" do
|
42
|
+
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
43
|
+
plainFile = File.new('plain.txt', 'wb+')
|
44
|
+
plainFile.puts(plainText)
|
45
|
+
plainFile.close()
|
46
|
+
rijndael = Crypt::Rijndael.new("Whatever happened to Yuri?")
|
47
|
+
rijndael.encrypt_file('plain.txt', 'crypt.txt')
|
48
|
+
rijndael.decrypt_file('crypt.txt', 'decrypt.txt')
|
49
|
+
decryptFile = File.new('decrypt.txt', 'rb')
|
50
|
+
decryptText = decryptFile.readlines().join('').chomp()
|
51
|
+
decryptFile.close()
|
52
|
+
expect(decryptText).to eql(plainText)
|
53
|
+
FileUtils.rm('plain.txt')
|
54
|
+
FileUtils.rm('crypt.txt')
|
55
|
+
FileUtils.rm('decrypt.txt')
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
CHANGED
@@ -1,60 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Kernahan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The Crypt library is a pure-ruby implementation of a number of popular
|
14
14
|
encryption algorithms. Block cyphers currently include Blowfish, GOST, IDEA, and
|
15
15
|
Rijndael (AES). Cypher Block Chaining (CBC) has been implemented, and unicode is
|
16
16
|
supported.
|
17
|
-
email:
|
17
|
+
email: recdev@finalstep.com.au
|
18
18
|
executables: []
|
19
19
|
extensions: []
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
-
- crypt/blowfish-tables.rb
|
23
|
-
- crypt/blowfish.rb
|
24
|
-
- crypt/cbc.rb
|
25
|
-
- crypt/gost.rb
|
26
|
-
- crypt/idea.rb
|
27
|
-
- crypt/noise.rb
|
28
|
-
- crypt/rijndael-tables.rb
|
29
|
-
- crypt/rijndael.rb
|
30
|
-
- crypt/stringxor.rb
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
35
|
-
|
36
|
-
- test/test-rijndael.rb
|
37
|
-
homepage: http://crypt.rubyforge.org/
|
22
|
+
- lib/crypt/blowfish-tables.rb
|
23
|
+
- lib/crypt/blowfish.rb
|
24
|
+
- lib/crypt/cbc.rb
|
25
|
+
- lib/crypt/gost.rb
|
26
|
+
- lib/crypt/idea.rb
|
27
|
+
- lib/crypt/noise.rb
|
28
|
+
- lib/crypt/rijndael-tables.rb
|
29
|
+
- lib/crypt/rijndael.rb
|
30
|
+
- lib/crypt/stringxor.rb
|
31
|
+
- specs/blowfish.rb
|
32
|
+
- specs/gost.rb
|
33
|
+
- specs/idea.rb
|
34
|
+
- specs/rijndael.rb
|
35
|
+
homepage: http://crypt.finalstep.com.au/
|
38
36
|
licenses:
|
39
37
|
- MIT
|
40
38
|
metadata: {}
|
41
39
|
post_install_message:
|
42
40
|
rdoc_options: []
|
43
41
|
require_paths:
|
44
|
-
- .
|
42
|
+
- "."
|
45
43
|
required_ruby_version: !ruby/object:Gem::Requirement
|
46
44
|
requirements:
|
47
|
-
- -
|
45
|
+
- - ">="
|
48
46
|
- !ruby/object:Gem::Version
|
49
47
|
version: '0'
|
50
48
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
49
|
requirements:
|
52
|
-
- -
|
50
|
+
- - ">="
|
53
51
|
- !ruby/object:Gem::Version
|
54
52
|
version: '0'
|
55
53
|
requirements: []
|
56
54
|
rubyforge_project: crypt
|
57
|
-
rubygems_version: 2.1
|
55
|
+
rubygems_version: 2.4.5.1
|
58
56
|
signing_key:
|
59
57
|
specification_version: 4
|
60
58
|
summary: Pure-ruby cryptographic library including Blowfish, GOST, IDEA, and Rijndael
|
data/crypt/stringxor.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# stringxor.rb Richard Kernahan <kernighan_rich@rubyforge.org>
|
2
|
-
|
3
|
-
module Crypt
|
4
|
-
module StringXor
|
5
|
-
|
6
|
-
|
7
|
-
def ^(aString)
|
8
|
-
a = self.unpack('C'*(self.length))
|
9
|
-
b = aString.unpack('C'*(aString.length))
|
10
|
-
if (b.length < a.length)
|
11
|
-
(a.length - b.length).times { b << 0 }
|
12
|
-
end
|
13
|
-
xor = "".force_encoding("ASCII-8BIT") # stop ruby 2 using Unicode
|
14
|
-
0.upto(a.length-1) { |pos|
|
15
|
-
x = a[pos] ^ b[pos]
|
16
|
-
xor << x.chr()
|
17
|
-
}
|
18
|
-
return(xor)
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class String
|
26
|
-
include Crypt::StringXor
|
27
|
-
end
|
data/test/break-idea.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# break-idea.rb Richard Kernahan <kernighan_rich@rubyforge.org>
|
2
|
-
# prove that IDEA is broken and try to find out why
|
3
|
-
|
4
|
-
require 'crypt/idea'
|
5
|
-
require 'crypt/blowfish'
|
6
|
-
|
7
|
-
# generate evidence for defect in IDEA implementation
|
8
|
-
# idea_en = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
9
|
-
# idea_de = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::DECRYPT)
|
10
|
-
# srand()
|
11
|
-
# puts "Finding pairs that fail to encrypt:"
|
12
|
-
# while(true)
|
13
|
-
# origL = rand(Crypt::IDEA::ULONG)
|
14
|
-
# origR = rand(Crypt::IDEA::ULONG)
|
15
|
-
# cl, cr = idea_en.crypt_pair(origL, origR)
|
16
|
-
# dl, dr = idea_de.crypt_pair(cl, cr)
|
17
|
-
# if ((origL != dl) | (origR != dr))
|
18
|
-
# cl, cr = idea_en.crypt_pair(origL, origR)
|
19
|
-
# dl, dr = idea_de.crypt_pair(cl, cr)
|
20
|
-
# if ((origL != dl) | (origR != dr))
|
21
|
-
# printf("[0x%-9x , 0x%-9x]\n", origL, origR)
|
22
|
-
# $stdout.flush()
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
# fatalPairs = [
|
27
|
-
# [0x5bb809a4, 0x804d4aba ],
|
28
|
-
# [0xead99b1 , 0xf64a62dd ],
|
29
|
-
# [0x50d72345, 0x4f6036d9 ],
|
30
|
-
# [0x32d41b94, 0x796a2eb5 ],
|
31
|
-
# [0x5d8a606e, 0x33befad ],
|
32
|
-
# [0x87b9dd21, 0xf5d9e7ce ],
|
33
|
-
# [0xd96be22c, 0x68fe08c9 ],
|
34
|
-
# [0x452131e8, 0xe687bd5 ],
|
35
|
-
# [0x827d9308, 0x512ace3d ],
|
36
|
-
# [0x5f0931d1, 0xb3b5c5c1 ],
|
37
|
-
# [0xd6dc1475, 0xf8964e8b ],
|
38
|
-
# [0xb7d7bba6, 0x8b8652e9 ],
|
39
|
-
# [0x2f42b24b, 0x6a889e95 ],
|
40
|
-
# [0x4e6eaebb, 0x99816f1 ]
|
41
|
-
# ]
|
42
|
-
# fatalPairs.each { |pair|
|
43
|
-
# origL, origR = pair
|
44
|
-
# cl, cr = idea_en.crypt_pair(origL, origR)
|
45
|
-
# dl, dr = idea_de.crypt_pair(cl, cr)
|
46
|
-
# if ((origL != dl) | (origR != dr))
|
47
|
-
# puts "still broken"
|
48
|
-
# end
|
49
|
-
# }
|
50
|
-
#idea = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
51
|
-
#(-3..0x10003).each { |a|
|
52
|
-
# inv = idea.mulInv(a)
|
53
|
-
# product = idea.mul(a, inv)
|
54
|
-
# if product != 1
|
55
|
-
# puts "a=#{a} inv=#{inv} mul(a,inv)=#{product}"
|
56
|
-
# $stdout.flush()
|
57
|
-
# end
|
58
|
-
#}
|
59
|
-
|
60
|
-
|
61
|
-
|
data/test/devServer.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# run the crypt website
|
2
|
-
|
3
|
-
require 'webrick'
|
4
|
-
include WEBrick
|
5
|
-
|
6
|
-
serverConfig = {
|
7
|
-
:Port => 80,
|
8
|
-
:Logger => WEBrick::Log.new($stderr, WEBrick::Log::ERROR),
|
9
|
-
:AccessLog => [[$stderr, WEBrick::AccessLog::COMBINED_LOG_FORMAT]]
|
10
|
-
}
|
11
|
-
server = WEBrick::HTTPServer.new(serverConfig)
|
12
|
-
server.mount("/", HTTPServlet::FileHandler, "C:/workspace/Crypt/site/", {:FancyIndexing => true})
|
13
|
-
server.mount("/crypt", HTTPServlet::FileHandler, "C:/workspace/Crypt/crypt/", {:FancyIndexing => true})
|
14
|
-
|
15
|
-
server.start
|
16
|
-
|
data/test/test-blowfish.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# test-blowfish.rb
|
2
|
-
# updated 11-Feb-2014 for ruby 2.0
|
3
|
-
|
4
|
-
require 'test/unit'
|
5
|
-
require 'crypt/blowfish'
|
6
|
-
require 'crypt/cbc'
|
7
|
-
require 'fileutils'
|
8
|
-
|
9
|
-
class TestBlowfish < Test::Unit::TestCase
|
10
|
-
|
11
|
-
def setup
|
12
|
-
@bf = Crypt::Blowfish.new("Who is John Galt?") # Schneier's test key
|
13
|
-
end
|
14
|
-
|
15
|
-
def teardown
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_block_size
|
19
|
-
assert_equal(8, @bf.block_size(), "Wrong block size")
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_initialize
|
23
|
-
assert_raise(RuntimeError) {
|
24
|
-
b0 = Crypt::Blowfish.new("")
|
25
|
-
}
|
26
|
-
assert_nothing_raised() {
|
27
|
-
b1 = Crypt::Blowfish.new("1")
|
28
|
-
}
|
29
|
-
assert_nothing_raised() {
|
30
|
-
b56 = Crypt::Blowfish.new("1"*56)
|
31
|
-
}
|
32
|
-
assert_raise(RuntimeError) {
|
33
|
-
b57 = Crypt::Blowfish.new("1"*57)
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_pair
|
38
|
-
bf = Crypt::Blowfish.new("Who is John Galt?")
|
39
|
-
orig_l, orig_r = [0xfedcba98, 0x76543210]
|
40
|
-
l, r = bf.encrypt_pair(orig_l, orig_r)
|
41
|
-
assert_equal(0xcc91732b, l)
|
42
|
-
assert_equal(0x8022f684, r)
|
43
|
-
l, r = bf.decrypt_pair(l, r)
|
44
|
-
assert_equal(orig_l, l)
|
45
|
-
assert_equal(orig_r, r)
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_block
|
49
|
-
bf = Crypt::Blowfish.new("Who is John Galt?")
|
50
|
-
block = "8 byte\u00cd" # unicode string of 8 bytes
|
51
|
-
encryptedBlock = bf.encrypt_block(block)
|
52
|
-
assert_equal("\xC4G\xD3\xFD7\xF4\x1E\xD0".force_encoding('ASCII-8BIT'), encryptedBlock)
|
53
|
-
decryptedBlock = bf.decrypt_block(encryptedBlock)
|
54
|
-
assert_equal(block, decryptedBlock)
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_string
|
58
|
-
length = 30 + rand(26)
|
59
|
-
userkey = ""
|
60
|
-
length.times { userkey << rand(256).chr }
|
61
|
-
bf = Crypt::Blowfish.new(userkey)
|
62
|
-
string = "This is a string which is not a multiple of 8 characters long"
|
63
|
-
encryptedString = bf.encrypt_string(string)
|
64
|
-
decryptedString = bf.decrypt_string(encryptedString)
|
65
|
-
assert_equal(string, decryptedString)
|
66
|
-
secondstring = "This is another string to check repetitive use."
|
67
|
-
encryptedString = bf.encrypt_string(secondstring)
|
68
|
-
decryptedString = bf.decrypt_string(encryptedString)
|
69
|
-
assert_equal(secondstring, decryptedString)
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_file
|
74
|
-
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
75
|
-
plainFile = File.new('plain.txt', 'wb+')
|
76
|
-
plainFile.puts(plainText)
|
77
|
-
plainFile.close()
|
78
|
-
bf = Crypt::Blowfish.new("Who is John Galt?")
|
79
|
-
bf.encrypt_file('plain.txt', 'crypt.txt')
|
80
|
-
bf.decrypt_file('crypt.txt', 'decrypt.txt')
|
81
|
-
decryptFile = File.new('decrypt.txt', 'rb')
|
82
|
-
decryptText = decryptFile.readlines().join('').chomp()
|
83
|
-
decryptFile.close()
|
84
|
-
assert_equal(plainText, decryptText)
|
85
|
-
FileUtils.rm('plain.txt')
|
86
|
-
FileUtils.rm('crypt.txt')
|
87
|
-
FileUtils.rm('decrypt.txt')
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
data/test/test-gost.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
# updated 11-Feb-2014 for ruby 2.0
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'crypt/gost'
|
5
|
-
require 'fileutils'
|
6
|
-
|
7
|
-
class TestGost < Test::Unit::TestCase
|
8
|
-
|
9
|
-
def setup
|
10
|
-
end
|
11
|
-
|
12
|
-
def teardown
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_init
|
16
|
-
assert_nothing_raised(RuntimeError) {
|
17
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri Gagarin?")
|
18
|
-
}
|
19
|
-
assert_nothing_raised(RuntimeError) {
|
20
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_block_size
|
25
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
26
|
-
assert_equal(8, gost.block_size(), "Wrong block size")
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_pair
|
30
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
31
|
-
orig_l, orig_r = [0xfedcba98, 0x76543210]
|
32
|
-
l, r = gost.encrypt_pair(orig_l, orig_r)
|
33
|
-
assert_equal(0xaefaf8f4, l)
|
34
|
-
assert_equal(0xe24891b0, r)
|
35
|
-
l, r = gost.decrypt_pair(l, r)
|
36
|
-
assert_equal(orig_l, l)
|
37
|
-
assert_equal(orig_r, r)
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_block
|
41
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
42
|
-
block = "norandom"
|
43
|
-
encryptedBlock = gost.encrypt_block(block)
|
44
|
-
assert_equal(".Vy\xFF\x05\e3`".force_encoding('ASCII-8BIT'), encryptedBlock)
|
45
|
-
decryptedBlock = gost.decrypt_block(encryptedBlock)
|
46
|
-
assert_equal(block, decryptedBlock)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_string
|
50
|
-
length = 25 + rand(12)
|
51
|
-
userkey = ""
|
52
|
-
length.times { userkey << rand(256).chr }
|
53
|
-
gost = Crypt::Gost.new(userkey)
|
54
|
-
string = "This is a string which is not a multiple of 8 characters long"
|
55
|
-
encryptedString = gost.encrypt_string(string)
|
56
|
-
decryptedString = gost.decrypt_string(encryptedString)
|
57
|
-
assert_equal(string, decryptedString)
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_file
|
61
|
-
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
62
|
-
plainFile = File.new('plain.txt', 'wb+')
|
63
|
-
plainFile.puts(plainText)
|
64
|
-
plainFile.close()
|
65
|
-
gost = Crypt::Gost.new("Whatever happened to Yuri?")
|
66
|
-
gost.encrypt_file('plain.txt', 'crypt.txt')
|
67
|
-
gost.decrypt_file('crypt.txt', 'decrypt.txt')
|
68
|
-
decryptFile = File.new('decrypt.txt', 'rb')
|
69
|
-
decryptText = decryptFile.readlines().join('').chomp()
|
70
|
-
decryptFile.close()
|
71
|
-
assert_equal(plainText, decryptText)
|
72
|
-
FileUtils.rm('plain.txt')
|
73
|
-
FileUtils.rm('crypt.txt')
|
74
|
-
FileUtils.rm('decrypt.txt')
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
data/test/test-idea.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
# updated 11-Feb-2014 for ruby 2.0 - changed expected values representation
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'crypt/idea'
|
5
|
-
require 'fileutils'
|
6
|
-
|
7
|
-
class TestIdea < Test::Unit::TestCase
|
8
|
-
|
9
|
-
def setup
|
10
|
-
end
|
11
|
-
|
12
|
-
def teardown
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_init
|
16
|
-
assert_nothing_raised(RuntimeError) {
|
17
|
-
idea_en = Crypt::IDEA.new("Who was John Galt and where's my breakfast?", Crypt::IDEA::ENCRYPT)
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_block_size
|
22
|
-
idea_en = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
23
|
-
assert_equal(8, idea_en.block_size(), "Wrong block size")
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_pair
|
27
|
-
idea_en = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
28
|
-
orig_l, orig_r = [0xfedcba98, 0x76543210]
|
29
|
-
l, r = idea_en.crypt_pair(orig_l, orig_r)
|
30
|
-
assert_equal(0x05627e79, l)
|
31
|
-
assert_equal(0x69476521, r)
|
32
|
-
idea_de = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::DECRYPT)
|
33
|
-
l, r = idea_de.crypt_pair(l, r)
|
34
|
-
assert_equal(orig_l, l)
|
35
|
-
assert_equal(orig_r, r)
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_block
|
39
|
-
idea_en = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
40
|
-
block = "8 byte\u00cd" # unicode string of 8 bytes
|
41
|
-
encryptedBlock = idea_en.encrypt_block(block)
|
42
|
-
expected = "\xFA\xB1P\tk\xB0\x1C\xE1".force_encoding("ASCII-8BIT")
|
43
|
-
assert_equal(expected, encryptedBlock)
|
44
|
-
idea_de = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::DECRYPT)
|
45
|
-
decryptedBlock = idea_de.decrypt_block(encryptedBlock)
|
46
|
-
assert_equal(block, decryptedBlock.force_encoding("UTF-8"))
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_string
|
50
|
-
length = 25 + rand(12)
|
51
|
-
userkey = ""
|
52
|
-
length.times { userkey << rand(256).chr }
|
53
|
-
idea_en = Crypt::IDEA.new(userkey, Crypt::IDEA::ENCRYPT)
|
54
|
-
string = "This is a string which is not a multiple of 8 characters long"
|
55
|
-
encryptedString = idea_en.encrypt_string(string)
|
56
|
-
idea_de = Crypt::IDEA.new(userkey, Crypt::IDEA::DECRYPT)
|
57
|
-
decryptedString = idea_de.decrypt_string(encryptedString)
|
58
|
-
assert_equal(string, decryptedString)
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_file
|
62
|
-
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
63
|
-
plainFile = File.new('plain.txt', 'wb+')
|
64
|
-
plainFile.puts(plainText)
|
65
|
-
plainFile.close()
|
66
|
-
idea_en = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::ENCRYPT)
|
67
|
-
idea_en.encrypt_file('plain.txt', 'crypt.txt')
|
68
|
-
idea_de = Crypt::IDEA.new("Who is John Galt", Crypt::IDEA::DECRYPT)
|
69
|
-
idea_de.decrypt_file('crypt.txt', 'decrypt.txt')
|
70
|
-
decryptFile = File.new('decrypt.txt', 'rb')
|
71
|
-
decryptText = decryptFile.readlines().join('').chomp()
|
72
|
-
decryptFile.close()
|
73
|
-
assert_equal(plainText, decryptText)
|
74
|
-
FileUtils.rm('plain.txt')
|
75
|
-
FileUtils.rm('crypt.txt')
|
76
|
-
FileUtils.rm('decrypt.txt')
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
data/test/test-rijndael.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# updated 11-Feb-2014 for ruby 2.0 - convert test strings into byte arrays, expected value representation
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'crypt/rijndael'
|
5
|
-
require 'fileutils'
|
6
|
-
|
7
|
-
class TestRijndael < Test::Unit::TestCase
|
8
|
-
|
9
|
-
def setup
|
10
|
-
end
|
11
|
-
|
12
|
-
def teardown
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_init
|
16
|
-
assert_raise(RuntimeError) {
|
17
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 64)
|
18
|
-
}
|
19
|
-
assert_raise(RuntimeError) {
|
20
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 64)
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_block_size
|
25
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 256)
|
26
|
-
assert_equal(32, rijndael.block_size)
|
27
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 256, 128)
|
28
|
-
assert_equal(16, rijndael.block_size)
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_block
|
32
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 128)
|
33
|
-
block = "This block \u00cd 16" # unicode string of 16 bytes
|
34
|
-
encryptedBlock = rijndael.encrypt_block(block)
|
35
|
-
assert_equal("\x8E\x88\x03\xB8> PnwR)\x93\x1A\xC9:\xC4".force_encoding("ASCII-8BIT"), encryptedBlock)
|
36
|
-
decryptedBlock = rijndael.decrypt_block(encryptedBlock)
|
37
|
-
assert_equal(block.force_encoding("ASCII-8BIT"), decryptedBlock)
|
38
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?", 128, 256)
|
39
|
-
assert_raise(RuntimeError) {
|
40
|
-
encryptedBlock = rijndael.encrypt_block(block)
|
41
|
-
}
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_string
|
45
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?")
|
46
|
-
string = "This is a string which is not a multiple of 8 characters long"
|
47
|
-
encryptedString = rijndael.encrypt_string(string)
|
48
|
-
decryptedString = rijndael.decrypt_string(encryptedString)
|
49
|
-
assert_equal(string, decryptedString)
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_file
|
53
|
-
plainText = "This is a multi-line string\nwhich is not a multiple of 8 \ncharacters long."
|
54
|
-
plainFile = File.new('plain.txt', 'wb+')
|
55
|
-
plainFile.puts(plainText)
|
56
|
-
plainFile.close()
|
57
|
-
rijndael = Crypt::Rijndael.new("Who is this John Galt guy, anyway?")
|
58
|
-
rijndael.encrypt_file('plain.txt', 'crypt.txt')
|
59
|
-
rijndael.decrypt_file('crypt.txt', 'decrypt.txt')
|
60
|
-
decryptFile = File.new('decrypt.txt', 'rb')
|
61
|
-
decryptText = decryptFile.readlines().join('').chomp()
|
62
|
-
decryptFile.close()
|
63
|
-
assert_equal(plainText, decryptText)
|
64
|
-
FileUtils.rm('plain.txt')
|
65
|
-
FileUtils.rm('crypt.txt')
|
66
|
-
FileUtils.rm('decrypt.txt')
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|