bitster 0.0.1c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.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
|