bitster 0.0.1c
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +4 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/bitster.gemspec +37 -0
- data/coverage/.last_run.json +5 -0
- data/coverage/.resultset.json +363 -0
- data/coverage/.resultset.json.lock +0 -0
- data/coverage/assets/0.10.0/application.css +799 -0
- data/coverage/assets/0.10.0/application.js +1707 -0
- data/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.10.0/loading.gif +0 -0
- data/coverage/assets/0.10.0/magnify.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +2290 -0
- data/examples/bitster.rb +58 -0
- data/examples/bitster.txt +9 -0
- data/examples/bitster_simple.rb +27 -0
- data/lib/bitster.rb +14 -0
- data/lib/bitster/crypto_math.rb +132 -0
- data/lib/bitster/rsa_key_pair.rb +87 -0
- data/lib/bitster/rsa_machine.rb +32 -0
- data/lib/bitster/rsa_private_key.rb +31 -0
- data/lib/bitster/rsa_pub_key.rb +28 -0
- data/lib/bitster/var_helpers.rb +13 -0
- data/lib/bitster/version.rb +3 -0
- metadata +232 -0
data/examples/bitster.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
$dev = true # flip this if running against an actually installed gem
|
2
|
+
|
3
|
+
if !$dev
|
4
|
+
require 'bitster'
|
5
|
+
else
|
6
|
+
require_relative '../lib/bitster/version'
|
7
|
+
require_relative '../lib/bitster/crypto_math'
|
8
|
+
require_relative '../lib/bitster/var_helpers'
|
9
|
+
require_relative '../lib/bitster/rsa_key_pair'
|
10
|
+
require_relative '../lib/bitster/rsa_pub_key'
|
11
|
+
require_relative '../lib/bitster/rsa_private_key'
|
12
|
+
require_relative '../lib/bitster/rsa_machine'
|
13
|
+
end
|
14
|
+
|
15
|
+
ciphertext = Array.new
|
16
|
+
result = Array.new
|
17
|
+
|
18
|
+
begin
|
19
|
+
plaintext = File.read(ARGV[0]).split("")
|
20
|
+
rescue
|
21
|
+
if $stdin.tty?
|
22
|
+
plaintext = ("C"*32).split("")
|
23
|
+
else
|
24
|
+
plaintext = ARGF.read.split("")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
key_len = 1024
|
29
|
+
print "[*] Generating a new RSA key-pair with modulus #{key_len}..."
|
30
|
+
t0 = Time.now.to_i
|
31
|
+
pair = Bitster::RSAKeyPair.new(key_len)
|
32
|
+
t1 = Time.now.to_i
|
33
|
+
puts " done; time elapsed: #{t1 - t0}s."
|
34
|
+
|
35
|
+
machine = Bitster::RSAMachine.new(:keypair => pair)
|
36
|
+
|
37
|
+
print "[*] Encrypting..."
|
38
|
+
t0 = Time.now.to_i
|
39
|
+
plaintext.each do |c|
|
40
|
+
ciphertext << machine.encrypt(c.ord)
|
41
|
+
end
|
42
|
+
t1 = Time.now.to_i
|
43
|
+
puts " done; time elapsed: #{t1 - t0}s."
|
44
|
+
|
45
|
+
|
46
|
+
print "[*] Decrypting..."
|
47
|
+
t0 = Time.now.to_i
|
48
|
+
ciphertext.each do |c|
|
49
|
+
result << machine.decrypt(c).chr
|
50
|
+
end
|
51
|
+
t1 = Time.now.to_i
|
52
|
+
puts " done; time elapsed: #{t1 - t0}s."
|
53
|
+
|
54
|
+
puts "[*] Result:"
|
55
|
+
puts "-"*80
|
56
|
+
puts result.join
|
57
|
+
puts "-"*80
|
58
|
+
puts "[*] -END-"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
RSA is one of the first practical public-key cryptosystems and is widely used
|
2
|
+
for secure data transmission. In such a cryptosystem, the encryption key is
|
3
|
+
public and differs from the decryption key which is kept secret. In RSA, this
|
4
|
+
asymmetry is based on the practical difficulty of factoring the product of two
|
5
|
+
large prime numbers, the factoring problem. RSA is made of the initial letters
|
6
|
+
of the surnames of Ron Rivest, Adi Shamir, and Leonard Adleman, who first
|
7
|
+
publicly described the algorithm in 1977. Clifford Cocks, an English mathe-
|
8
|
+
matician working for the UK intelligence agency GCHQ, had developed an equi-
|
9
|
+
valent system in 1973, but it was not declassified until 1997.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
$dev = true # flip this if running against an actually installed gem
|
2
|
+
|
3
|
+
if !$dev
|
4
|
+
require 'bitster'
|
5
|
+
else
|
6
|
+
require_relative '../lib/bitster/version'
|
7
|
+
require_relative '../lib/bitster/crypto_math'
|
8
|
+
require_relative '../lib/bitster/var_helpers'
|
9
|
+
require_relative '../lib/bitster/rsa_key_pair'
|
10
|
+
require_relative '../lib/bitster/rsa_pub_key'
|
11
|
+
require_relative '../lib/bitster/rsa_private_key'
|
12
|
+
require_relative '../lib/bitster/rsa_machine'
|
13
|
+
end
|
14
|
+
|
15
|
+
key_pair = Bitster::RSAKeyPair.new(1024)
|
16
|
+
machine = Bitster::RSAMachine.new(:keypair => key_pair)
|
17
|
+
|
18
|
+
ciphertext = %w(H E L L O).collect do |char|
|
19
|
+
machine.encrypt(char.ord)
|
20
|
+
end
|
21
|
+
|
22
|
+
plaintext = ciphertext.collect do |ascii_code|
|
23
|
+
machine.decrypt(ascii_code).chr
|
24
|
+
end.join('')
|
25
|
+
|
26
|
+
puts plaintext
|
27
|
+
|
data/lib/bitster.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bitster/version'
|
2
|
+
require 'bitster/crypto_math'
|
3
|
+
require 'bitster/var_helpers'
|
4
|
+
require 'bitster/rsa_key_pair'
|
5
|
+
require 'bitster/rsa_pub_key'
|
6
|
+
require 'bitster/rsa_private_key'
|
7
|
+
require 'bitster/rsa_machine'
|
8
|
+
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
module Bitster
|
13
|
+
include self::CryptoMath
|
14
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Bitster
|
2
|
+
|
3
|
+
# This module implements mathematical functions needed by the RSA layer,
|
4
|
+
# i.e. primality tests, modular arithmetic, and random odd number generation.
|
5
|
+
#
|
6
|
+
# ToDo: Error handling (with custom Exception class, etc.)
|
7
|
+
#
|
8
|
+
module CryptoMath
|
9
|
+
|
10
|
+
# This function performs what is known as Modular exponentiation
|
11
|
+
# https://en.wikipedia.org/wiki/Modular_exponentiation
|
12
|
+
#
|
13
|
+
# Modular exponentiation are easy to compute, even when the numbers
|
14
|
+
# involved are enormous.
|
15
|
+
#
|
16
|
+
def modular_pow(base, exponent, modulus)
|
17
|
+
return nil if modulus == 1
|
18
|
+
result = 1
|
19
|
+
base = base % modulus
|
20
|
+
while exponent > 0 do
|
21
|
+
if (exponent % 2) == 1
|
22
|
+
result = (result * base) % modulus
|
23
|
+
end
|
24
|
+
exponent = exponent >> 1
|
25
|
+
base = (base * base) % modulus
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
# This function just combines Fermat test and Rabin-Miller test.
|
31
|
+
# If both witness the primality, we consider the argument a
|
32
|
+
# probable prime
|
33
|
+
#
|
34
|
+
# ToDo: How to calculate an optimal number of RM rounds instead of 7?
|
35
|
+
#
|
36
|
+
def probable_prime?(p, k=7)
|
37
|
+
fermat_prime?(p) && rm_prime?(p, k)
|
38
|
+
end
|
39
|
+
|
40
|
+
# This is Fermat primality test.
|
41
|
+
# https://en.wikipedia.org/wiki/Fermat_primality_test
|
42
|
+
#
|
43
|
+
# ToDo: How to really choose "a" and how many iterations to run?
|
44
|
+
#
|
45
|
+
def fermat_prime?(p)
|
46
|
+
raise ArgumentError, 'Argument must be an Integer greater than 3' unless p.is_a?(Integer) && (p>3)
|
47
|
+
[p-1, p/2, p/3, p/4, 1].each do |a|
|
48
|
+
# return false if (a**(p-1) % p) != (1 % p)
|
49
|
+
return false if modular_pow(a, (p-1), p) != (1 % p)
|
50
|
+
end
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
# This is Rabin-Miller primality test
|
55
|
+
# https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
|
56
|
+
#
|
57
|
+
def rm_prime?(n, k)
|
58
|
+
r=0; d=0
|
59
|
+
(1..128).each do |i|
|
60
|
+
d = n / (2**i)
|
61
|
+
r = i
|
62
|
+
break unless (d % 2) == 0
|
63
|
+
end
|
64
|
+
k.times do
|
65
|
+
flg = false
|
66
|
+
a = rand(2..(n-2))
|
67
|
+
x = modular_pow(a, d, n)
|
68
|
+
if (x == 1) || (x == (n - 1))
|
69
|
+
next
|
70
|
+
end
|
71
|
+
(r-1).times do
|
72
|
+
x = modular_pow(x, 2, n)
|
73
|
+
return false if x == 1
|
74
|
+
if x == (n - 1)
|
75
|
+
flg = true
|
76
|
+
break
|
77
|
+
end
|
78
|
+
end
|
79
|
+
next if flg
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
# This function generates a random odd integer in a range of
|
86
|
+
# 2^(bits-1) ... 2^(bits)
|
87
|
+
#
|
88
|
+
# ToDo: What should the minimum really be?
|
89
|
+
#
|
90
|
+
def gen_odd(bits)
|
91
|
+
max = 2**bits
|
92
|
+
min = 2**(bits-1)
|
93
|
+
r = rand(min..max)
|
94
|
+
return r - 1 if r%2 == 0
|
95
|
+
r
|
96
|
+
end
|
97
|
+
|
98
|
+
# This function calculates the Modular multiplicative inverse
|
99
|
+
# which is needed in the key generation process.
|
100
|
+
# https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
|
101
|
+
#
|
102
|
+
def modular_multiplicative_inverse(a, n)
|
103
|
+
t = 0
|
104
|
+
nt = 1
|
105
|
+
r = n
|
106
|
+
nr = a % n
|
107
|
+
|
108
|
+
if n < 0
|
109
|
+
n = -n
|
110
|
+
end
|
111
|
+
if a < 0
|
112
|
+
a = n - (-a % n)
|
113
|
+
end
|
114
|
+
while nr != 0 do
|
115
|
+
quot = 0
|
116
|
+
quot = (r/nr) unless (r/nr) == 0
|
117
|
+
tmp = nt; nt = t - quot*nt; t = tmp
|
118
|
+
tmp = nr; nr = r - quot*nr; r = tmp
|
119
|
+
end
|
120
|
+
if r > 1
|
121
|
+
raise StandardError, "#{a} and #{n} are not coprimes, can't find MMI"
|
122
|
+
end
|
123
|
+
if t < 0
|
124
|
+
t += n
|
125
|
+
end
|
126
|
+
t
|
127
|
+
end
|
128
|
+
|
129
|
+
extend self
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Bitster
|
2
|
+
|
3
|
+
# This class represents a RSA key-pair. The most important feature is the
|
4
|
+
# generation of the key-pair, so it is an implementation of the process
|
5
|
+
# outlined in https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation
|
6
|
+
#
|
7
|
+
class RSAKeyPair
|
8
|
+
|
9
|
+
class RSAKeyPairError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :len, :shorter, :p, :q, :n, :k, :e, :private_key, :public_key
|
13
|
+
|
14
|
+
def initialize(len)
|
15
|
+
@len = len
|
16
|
+
|
17
|
+
@shorter = rand(0..1)
|
18
|
+
@p = gen_p
|
19
|
+
@q = gen_q
|
20
|
+
@n = @p * @q # modulus
|
21
|
+
@k = gen_totient
|
22
|
+
@e = gen_e # pubkey exponent
|
23
|
+
@d = gen_d # prikey exponent
|
24
|
+
|
25
|
+
@private_key = RSAPrivateKey.new(@p, @q, @d, @len)
|
26
|
+
@public_key = RSAPubKey.new(@n, @e, @len)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
include CryptoMath
|
32
|
+
|
33
|
+
# ToDo: what should the length difference of p and q really be?
|
34
|
+
def gen_p
|
35
|
+
handle_exceptions do
|
36
|
+
len_p = @len/2
|
37
|
+
len_p -= rand(2..4) if @shorter == 0
|
38
|
+
loop do
|
39
|
+
p = gen_odd(len_p)
|
40
|
+
return p if probable_prime?(p)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# ToDo: what should the length difference of p and q really be?
|
46
|
+
def gen_q
|
47
|
+
handle_exceptions do
|
48
|
+
len_q = @len/2
|
49
|
+
len_q -= rand(2..4) if @shorter == 1
|
50
|
+
loop do
|
51
|
+
q = gen_odd(len_q)
|
52
|
+
return q if probable_prime?(q)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def gen_totient
|
58
|
+
handle_exceptions do
|
59
|
+
(@p-1)*(@q-1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# ToDo: what should the lower bound really be?
|
64
|
+
def gen_e
|
65
|
+
handle_exceptions do
|
66
|
+
loop do
|
67
|
+
e = rand(4..@k)
|
68
|
+
return e if e.gcd(@k) == 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def gen_d
|
74
|
+
handle_exceptions do
|
75
|
+
modular_multiplicative_inverse(e, k)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_exceptions
|
80
|
+
begin
|
81
|
+
yield
|
82
|
+
rescue StandardError => e
|
83
|
+
raise RSAKeyPairError, "Exception in RSAKeyPair: #{e}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Bitster
|
2
|
+
|
3
|
+
# This class implements RSA encryption and decryption functions.
|
4
|
+
# It is initialized with necessary keys, represented as instances
|
5
|
+
# of their according classes.
|
6
|
+
#
|
7
|
+
class RSAMachine
|
8
|
+
attr_accessor :pubkey, :prikey
|
9
|
+
|
10
|
+
def initialize(opts={})
|
11
|
+
@pubkey = opts[:pubkey] if opts.has_key?(:pubkey)
|
12
|
+
@prikey = opts[:prikey] if opts.has_key?(:prikey)
|
13
|
+
if opts.has_key?(:keypair)
|
14
|
+
@pubkey = opts[:keypair].public_key
|
15
|
+
@prikey = opts[:keypair].private_key
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Encryption
|
20
|
+
#
|
21
|
+
def encrypt(plaintext_msg_code)
|
22
|
+
CryptoMath::modular_pow(plaintext_msg_code, @pubkey.exponent, @pubkey.modulus)
|
23
|
+
end
|
24
|
+
|
25
|
+
# https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Decryption
|
26
|
+
#
|
27
|
+
def decrypt(ciphertext_msg_code)
|
28
|
+
CryptoMath::modular_pow(ciphertext_msg_code, @prikey.exponent, @prikey.modulus)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bitster
|
2
|
+
|
3
|
+
# This class represents RSA private key and provides various
|
4
|
+
# formatting and similar helper methods associated with it.
|
5
|
+
#
|
6
|
+
class RSAPrivateKey
|
7
|
+
|
8
|
+
attr_reader :modulus, :exponent, :len, :p, :q
|
9
|
+
|
10
|
+
def initialize(p, q, exponent, len)
|
11
|
+
@exponent = exponent
|
12
|
+
@modulus = p*q
|
13
|
+
@p = p; @q = q
|
14
|
+
@len = len
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_hash
|
18
|
+
{ modulus: pad(@modulus, 16, @len), exponent: pad(@exponent, 16, @len) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_json
|
22
|
+
JSON.pretty_generate get_hash
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
include VarHelpers
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Bitster
|
2
|
+
|
3
|
+
# This class represents RSA public key and provides various
|
4
|
+
# formatting and similar helper methods associated with it.
|
5
|
+
#
|
6
|
+
class RSAPubKey
|
7
|
+
|
8
|
+
attr_reader :modulus, :exponent, :len
|
9
|
+
|
10
|
+
def initialize(modulus, exponent, len)
|
11
|
+
@modulus = modulus
|
12
|
+
@exponent = exponent
|
13
|
+
@len = len
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_hash
|
17
|
+
{ modulus: pad(@modulus, 16, @len), exponent: pad(@exponent, 16, @len) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_json
|
21
|
+
JSON.pretty_generate get_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
include VarHelpers
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|