block-tea 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +45 -0
- data/bin/block_tea +17 -0
- data/lib/crypt.rb +1 -0
- data/lib/crypt/block_tea.rb +113 -0
- data/test/benchmark.rb +56 -0
- data/test/test_block_tea.rb +62 -0
- metadata +73 -0
data/README.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= Crypt::BlockTEA
|
2
|
+
|
3
|
+
This is a fork of * http://crypt-tea.rubyforge.org/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
An implementation of the Tiny Encryption Algorithm that's compatible with PHP's xxTEA
|
8
|
+
|
9
|
+
|
10
|
+
== USAGE:
|
11
|
+
|
12
|
+
k = Crypt::BlockTEA.new("e43f3fd0bd91bef1")
|
13
|
+
puts a = k.encrypt('Hello from the Moon')
|
14
|
+
puts k.decrypt('eEBikks7C1IlSCYA0cECdrdKSLA=')
|
15
|
+
|
16
|
+
|
17
|
+
== TODO:
|
18
|
+
|
19
|
+
Bi-directional interface to interact with JavaScript (http://www.movable-type.co.uk/scripts/tea-block.html)
|
20
|
+
Tests
|
21
|
+
|
22
|
+
== LICENSE:
|
23
|
+
|
24
|
+
(The MIT License)
|
25
|
+
|
26
|
+
Copyright (c) 2011 Mikhailov Anatoly
|
27
|
+
|
28
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
29
|
+
a copy of this software and associated documentation files (the
|
30
|
+
'Software'), to deal in the Software without restriction, including
|
31
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
32
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
33
|
+
permit persons to whom the Software is furnished to do so, subject to
|
34
|
+
the following conditions:
|
35
|
+
|
36
|
+
The above copyright notice and this permission notice shall be
|
37
|
+
included in all copies or substantial portions of the Software.
|
38
|
+
|
39
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
40
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
41
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
42
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
43
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
44
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
45
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/block_tea
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
unless (ARGV.length == 3) && (command = ARGV[0][/^enc/] ? :encrypt : (ARGV[0][/^dec/] ? :decrypt : nil))
|
4
|
+
puts ' Usage:'
|
5
|
+
puts " block_tea <command> <key> <plaintext/cyphertext>"
|
6
|
+
puts
|
7
|
+
puts " Commands:"
|
8
|
+
puts " enc, encrypt"
|
9
|
+
puts " dec, decrypt"
|
10
|
+
puts
|
11
|
+
else
|
12
|
+
require 'rubygems'
|
13
|
+
require 'block_tea'
|
14
|
+
|
15
|
+
k = Crypt::BlockTEA.new(ARGV[1].dup)
|
16
|
+
puts k.send(command, ARGV[2].dup)
|
17
|
+
end
|
data/lib/crypt.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[crypt block_tea])
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Crypt
|
2
|
+
class BlockTEA
|
3
|
+
DELTA = 0x9E3779B9
|
4
|
+
|
5
|
+
def initialize(password)
|
6
|
+
@password = password
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# encrypt: Use Corrected Block TEA to encrypt plaintext using password
|
11
|
+
# Return encrypted text as string
|
12
|
+
def encrypt(plaintext)
|
13
|
+
if plaintext.length == 0
|
14
|
+
return('') # nothing to encrypt
|
15
|
+
end
|
16
|
+
|
17
|
+
# 'escape' plaintext so chars outside ISO-8859-1 work in single-byte packing, but
|
18
|
+
# keep spaces as spaces (not '%20') so encrypted text doesn't grow too long, and
|
19
|
+
# convert result to longs
|
20
|
+
# v = str_to_longs(escape(plaintext).gsub(/%20/,' '))
|
21
|
+
v = str_to_longs(plaintext)
|
22
|
+
|
23
|
+
if v.length == 1
|
24
|
+
v[1] = 0 # algorithm doesn't work for n<2 so fudge by adding nulls
|
25
|
+
end
|
26
|
+
|
27
|
+
k = str_to_longs(@password.ljust(16).slice(0,16)) # simply convert first 16 chars of password as key
|
28
|
+
n = v.length
|
29
|
+
|
30
|
+
z = v[n-1]
|
31
|
+
y = v[0]
|
32
|
+
sum = 0
|
33
|
+
|
34
|
+
(6 + 52.0/n).floor.downto(1) { |q| # 6 + 52/n operations gives between 6 & 32 mixes on each word
|
35
|
+
sum = (sum + DELTA) & 0xffffffff
|
36
|
+
e = sum>>2 & 3
|
37
|
+
for p in (0...n-1)
|
38
|
+
y = v[p+1]
|
39
|
+
v[p] = (v[p] + mx(z, y, sum, k[p&3 ^ e])) & 0xffffffff
|
40
|
+
z = v[p]
|
41
|
+
end
|
42
|
+
y = v[0]
|
43
|
+
v[n-1] = (v[n-1] + mx(z, y, sum, k[(n-1)&3 ^ e])) & 0xffffffff
|
44
|
+
z = v[n-1]
|
45
|
+
}
|
46
|
+
|
47
|
+
ciphertext = longs_to_str(v)
|
48
|
+
return ciphertext.unpack('a*').pack('m').delete("\n") # base64 encode it without newlines
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# decrypt: Use Corrected Block TEA to decrypt ciphertext using password
|
53
|
+
def decrypt(ciphertext)
|
54
|
+
if ciphertext.length == 0
|
55
|
+
return('')
|
56
|
+
end
|
57
|
+
|
58
|
+
v = str_to_longs(ciphertext.unpack('m').pack("a*")) # base64 decode and convert to array of 'longs'
|
59
|
+
k = str_to_longs(@password.ljust(16).slice(0,16))
|
60
|
+
n = v.length
|
61
|
+
|
62
|
+
z = v[n-1]
|
63
|
+
y = v[0]
|
64
|
+
q = (6 + 52.0/n).floor
|
65
|
+
sum = q*DELTA
|
66
|
+
|
67
|
+
while (sum > 0)
|
68
|
+
e = sum>>2 & 3
|
69
|
+
(n-1).downto(1) { |p|
|
70
|
+
z = v[p-1]
|
71
|
+
v[p] = (v[p] - mx(z, y, sum, k[p&3 ^ e])) & 0xffffffff
|
72
|
+
y = v[p]
|
73
|
+
}
|
74
|
+
|
75
|
+
z = v[n-1]
|
76
|
+
v[0] = (v[0] - mx(z, y, sum, k[0 ^ e])) & 0xffffffff
|
77
|
+
y = v[0]
|
78
|
+
sum -= DELTA
|
79
|
+
end
|
80
|
+
|
81
|
+
plaintext = longs_to_str(v)
|
82
|
+
# strip trailing null chars resulting from filling 4-char blocks:
|
83
|
+
plaintext = plaintext.gsub(/\0+$/,'')
|
84
|
+
return plaintext
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
|
91
|
+
def mx(z, y, sum, p)
|
92
|
+
((z>>5 ^ ((y<<2)&0xffffffff)) + (y>>3 ^ ((z<<4)&0xffffffff)) ^ (sum^y) + (p ^ z)) & 0xffffffff
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.str_to_longs(s, include_count = false)
|
96
|
+
s << [0,0,0].pack('c*') # Pad with at most three nulls
|
97
|
+
return s.unpack('L*')
|
98
|
+
end
|
99
|
+
|
100
|
+
def str_to_longs(s, include_count = false) # :nodoc:
|
101
|
+
self.class.str_to_longs s, include_count
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.longs_to_str(l, include_count = false) # convert array of longs back to string
|
105
|
+
l.pack('L*')
|
106
|
+
end
|
107
|
+
|
108
|
+
def longs_to_str(l, include_count = false) # :nodoc:
|
109
|
+
self.class.longs_to_str l, include_count
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
data/test/benchmark.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'benchmark'
|
3
|
+
require File.join(File.dirname(__FILE__), *%w[.. lib crypt])
|
4
|
+
|
5
|
+
KEY = Crypt::BlockTEA.new 'abigfattestkey'
|
6
|
+
STRINGS = {}
|
7
|
+
|
8
|
+
CHARS = [('a'..'z'),('A'..'Z'),('0'..'9')].map{|i| i.to_a}.flatten
|
9
|
+
def rand_string(size)
|
10
|
+
(0...size).map { CHARS[rand(CHARS.length)] }.join
|
11
|
+
end
|
12
|
+
|
13
|
+
Benchmark.bm do |x|
|
14
|
+
[1, 10, 100, 1_000, 10_000, 100_000].each do |size|
|
15
|
+
STRINGS[size] = rand_string(size)
|
16
|
+
x.report(size.to_s.rjust(6)) { KEY.decrypt(KEY.encrypt(STRINGS[size])) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
__END__
|
21
|
+
|
22
|
+
Ruby 1.8.6
|
23
|
+
user system total real
|
24
|
+
1 0.000000 0.000000 0.000000 ( 0.002733)
|
25
|
+
10 0.000000 0.000000 0.000000 ( 0.003002)
|
26
|
+
100 0.010000 0.010000 0.020000 ( 0.007730)
|
27
|
+
1000 0.070000 0.000000 0.070000 ( 0.077805)
|
28
|
+
10000 0.720000 0.010000 0.730000 ( 0.738411)
|
29
|
+
100000 7.780000 0.040000 7.820000 ( 7.932519)
|
30
|
+
|
31
|
+
Ruby 1.9.1p129
|
32
|
+
user system total real
|
33
|
+
1 0.010000 0.000000 0.010000 ( 0.013437)
|
34
|
+
10 0.000000 0.000000 0.000000 ( 0.001345)
|
35
|
+
100 0.000000 0.000000 0.000000 ( 0.003279)
|
36
|
+
1000 0.040000 0.000000 0.040000 ( 0.040562)
|
37
|
+
10000 0.390000 0.010000 0.400000 ( 0.402591)
|
38
|
+
100000 3.170000 0.020000 3.190000 ( 3.243170)
|
39
|
+
|
40
|
+
jRuby 1.2.0
|
41
|
+
user system total real
|
42
|
+
1 0.026000 0.000000 0.026000 ( 0.026000)
|
43
|
+
10 0.018000 0.000000 0.018000 ( 0.018000)
|
44
|
+
100 0.040000 0.000000 0.040000 ( 0.040000)
|
45
|
+
1000 0.220000 0.000000 0.220000 ( 0.220000)
|
46
|
+
10000 0.682000 0.000000 0.682000 ( 0.682000)
|
47
|
+
100000 1.281000 0.000000 1.281000 ( 1.281000)
|
48
|
+
|
49
|
+
jRuby 1.3.0RC2
|
50
|
+
user system total real
|
51
|
+
1 0.026000 0.000000 0.026000 ( 0.025000)
|
52
|
+
10 0.020000 0.000000 0.020000 ( 0.020000)
|
53
|
+
100 0.040000 0.000000 0.040000 ( 0.041000)
|
54
|
+
1000 0.255000 0.000000 0.255000 ( 0.254000)
|
55
|
+
10000 0.499000 0.000000 0.499000 ( 0.500000)
|
56
|
+
100000 1.805000 0.000000 1.805000 ( 1.806000)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/spec'
|
3
|
+
require File.join(File.dirname(__FILE__), *%w[.. lib crypt])
|
4
|
+
|
5
|
+
MiniTest::Unit.autorun
|
6
|
+
|
7
|
+
describe Crypt::BlockTEA do
|
8
|
+
# before do
|
9
|
+
# @key_text = 'abigfattestkey'
|
10
|
+
# @key = Crypt::BlockTEA.new @key_text
|
11
|
+
# @plaintext = "Oh say can you see, by the dawn's early light"
|
12
|
+
# @cyphertext = "V32cYZc5yLXepm9lxzr4kgGM/eSVurwV0yQWi4uFs0uB2UBlJ19ZRKKMkbMr7DLGc3n1XQ=="
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# it 'converts strings to longs' do
|
16
|
+
# Crypt::BlockTEA.str_to_longs('testing', true).must_equal [1953719668, 6778473, 7]
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# it 'converts longs to strings' do
|
20
|
+
# Crypt::BlockTEA.longs_to_str([1953719668, 6778473, 7], true).must_equal 'testing'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# it 'raises an error when the key is too long' do
|
24
|
+
# proc { Crypt::BlockTEA.new '12345678901234567' }.must_raise RuntimeError
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# it 'raises an error when the key is blank' do
|
28
|
+
# proc { Crypt::BlockTEA.new '' }.must_raise RuntimeError
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# it 'works properly with small keys' do
|
32
|
+
# key = Crypt::BlockTEA.new '123'
|
33
|
+
# cyphertext = key.encrypt(@plaintext)
|
34
|
+
# key.decrypt(cyphertext).must_equal @plaintext
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# it 'properly encrypts when instantiated' do
|
38
|
+
# @key.encrypt(@plaintext).must_equal @cyphertext
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# it 'properly decrypts when instantiated' do
|
42
|
+
# @key.decrypt(@cyphertext).must_equal @plaintext
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# it 'properly en/decrypts tiny text' do
|
46
|
+
# txt = '1'
|
47
|
+
# @key.decrypt(@key.encrypt(txt)).must_equal txt
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# it 'properly en/decrypts huge text' do
|
51
|
+
# str = '1234567890' * 1_000
|
52
|
+
# @key.decrypt(@key.encrypt(str)).must_equal str
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# it 'properly encrypts with a class method' do
|
56
|
+
# Crypt::BlockTEA.encrypt(@key_text, @plaintext).must_equal @cyphertext
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# it 'properly decrypts with a class method' do
|
60
|
+
# Crypt::BlockTEA.decrypt(@key_text, @cyphertext).must_equal @plaintext
|
61
|
+
# end
|
62
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: block-tea
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
- 1
|
10
|
+
version: 1.3.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Mikhailov Anatoly
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-09 00:00:00 +06:00
|
19
|
+
default_executable: block_tea
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A fork of an implementation of the Tiny Encryption Algorithm that's compatible with PHP's xxTEA
|
23
|
+
email: mikhailov.anatoly@gmail.com
|
24
|
+
executables:
|
25
|
+
- block_tea
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.rdoc
|
30
|
+
files:
|
31
|
+
- bin/block_tea
|
32
|
+
- lib/crypt.rb
|
33
|
+
- lib/crypt/block_tea.rb
|
34
|
+
- README.rdoc
|
35
|
+
- test/benchmark.rb
|
36
|
+
- test/test_block_tea.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: ""
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: ""
|
67
|
+
rubygems_version: 1.4.2
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: xxTEA implemented in pure ruby
|
71
|
+
test_files:
|
72
|
+
- test/benchmark.rb
|
73
|
+
- test/test_block_tea.rb
|