crypt 2.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|