rsa 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +1 -0
- data/CREDITS +0 -0
- data/README +88 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/lib/rsa.rb +26 -0
- data/lib/rsa/key.rb +54 -0
- data/lib/rsa/key_pair.rb +155 -0
- data/lib/rsa/math.rb +100 -0
- data/lib/rsa/openssl.rb +37 -0
- data/lib/rsa/pkcs1.rb +124 -0
- data/lib/rsa/version.rb +22 -0
- metadata +102 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* Arto Bendiken <arto.bendiken@gmail.com>
|
data/CREDITS
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
RSA.rb: RSA Encryption for Ruby
|
2
|
+
===============================
|
3
|
+
|
4
|
+
RSA.rb is a [Ruby][] library that implements the [RSA][] encryption
|
5
|
+
algorithm and the [PKCS#1][] cryptography standard.
|
6
|
+
|
7
|
+
* <http://github.com/bendiken/rsa>
|
8
|
+
|
9
|
+
Features
|
10
|
+
--------
|
11
|
+
|
12
|
+
* 100% free and unencumbered [public domain](http://unlicense.org/) software.
|
13
|
+
* Implements the PKCS#1 data conversion primitives (I2OSP and OS2IP).
|
14
|
+
* Implements the PKCS#1 encryption/decryption primitives (RSAEP and RSADP).
|
15
|
+
* Implements the PKCS#1 signature primitives (RSASP1 and RSAVP1).
|
16
|
+
* Implements RSA key pair generation using Ruby's OpenSSL standard library.
|
17
|
+
* Compatible with Ruby 1.9.1+ and JRuby 1.5.0+.
|
18
|
+
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
19
|
+
|
20
|
+
Documentation
|
21
|
+
-------------
|
22
|
+
|
23
|
+
* <http://rsa.rubyforge.org/>
|
24
|
+
|
25
|
+
Dependencies
|
26
|
+
------------
|
27
|
+
|
28
|
+
* [Ruby](http://ruby-lang.org/) (>= 1.9.1) or (>= 1.8.1 with [Backports][])
|
29
|
+
|
30
|
+
Installation
|
31
|
+
------------
|
32
|
+
|
33
|
+
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
34
|
+
To install the latest official release of RSA.rb, do:
|
35
|
+
|
36
|
+
% [sudo] gem install rsa # Ruby 1.9.1+
|
37
|
+
% [sudo] gem install backports rsa # Ruby 1.8.x
|
38
|
+
|
39
|
+
Download
|
40
|
+
--------
|
41
|
+
|
42
|
+
To get a local working copy of the development repository, do:
|
43
|
+
|
44
|
+
% git clone git://github.com/bendiken/rsa.git
|
45
|
+
|
46
|
+
Alternatively, you can download the latest development version as a tarball
|
47
|
+
as follows:
|
48
|
+
|
49
|
+
% wget http://github.com/bendiken/rsa/tarball/master
|
50
|
+
|
51
|
+
Author
|
52
|
+
------
|
53
|
+
|
54
|
+
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
|
55
|
+
|
56
|
+
Contributors
|
57
|
+
------------
|
58
|
+
|
59
|
+
Refer to the accompanying {file:CREDITS} file.
|
60
|
+
|
61
|
+
Contributing
|
62
|
+
------------
|
63
|
+
|
64
|
+
* Do your best to adhere to the existing coding conventions and idioms.
|
65
|
+
* Don't use hard tabs, and don't leave trailing whitespace on any line.
|
66
|
+
* Do document every method you add using [YARD][] annotations. Read the
|
67
|
+
[tutorial][YARD-GS] or just look at the existing code for examples.
|
68
|
+
* Don't touch the `.gemspec`, `VERSION` or `AUTHORS` files. If you need to
|
69
|
+
change them, do so on your private branch only.
|
70
|
+
* Do feel free to add yourself to the `CREDITS` file and the corresponding
|
71
|
+
list in the the `README`. Alphabetical order applies.
|
72
|
+
* Do note that in order for us to merge any non-trivial changes (as a rule
|
73
|
+
of thumb, additions larger than about 15 lines of code), we need an
|
74
|
+
explicit [public domain dedication][PDD] on record from you.
|
75
|
+
|
76
|
+
License
|
77
|
+
-------
|
78
|
+
|
79
|
+
This is free and unencumbered public domain software. For more information,
|
80
|
+
see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
81
|
+
|
82
|
+
[Ruby]: http://ruby-lang.org/
|
83
|
+
[RSA]: http://en.wikipedia.org/wiki/RSA
|
84
|
+
[PKCS#1]: http://en.wikipedia.org/wiki/PKCS1
|
85
|
+
[YARD]: http://yardoc.org/
|
86
|
+
[YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
87
|
+
[PDD]: http://unlicense.org/#unlicensing-contributions
|
88
|
+
[Backports]: http://rubygems.org/gems/backports
|
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/rsa.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'stringio' unless defined?(StringIO)
|
2
|
+
|
3
|
+
if RUBY_VERSION < '1.9.1'
|
4
|
+
# @see http://rubygems.org/gems/backports
|
5
|
+
begin
|
6
|
+
require 'backports/1.9.1'
|
7
|
+
rescue LoadError
|
8
|
+
abort "RSA.rb requires Ruby 1.9.1 or the Backports gem (hint: `gem install backports')."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module RSA
|
13
|
+
autoload :Math, 'rsa/math'
|
14
|
+
autoload :PKCS1, 'rsa/pkcs1'
|
15
|
+
autoload :Key, 'rsa/key'
|
16
|
+
autoload :KeyPair, 'rsa/key_pair'
|
17
|
+
autoload :OpenSSL, 'rsa/openssl'
|
18
|
+
autoload :VERSION, 'rsa/version'
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'openssl'
|
23
|
+
require 'rsa/openssl'
|
24
|
+
rescue LoadError
|
25
|
+
# OpenSSL acceleration disabled.
|
26
|
+
end
|
data/lib/rsa/key.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module RSA
|
2
|
+
##
|
3
|
+
# An RSA public or private key.
|
4
|
+
#
|
5
|
+
# Refer to PKCS #1 v2.1, section 3, pp. 6-8.
|
6
|
+
#
|
7
|
+
# @see http://www.rsa.com/rsalabs/node.asp?id=2125
|
8
|
+
# @see http://en.wikipedia.org/wiki/Public-key_cryptography
|
9
|
+
class Key
|
10
|
+
##
|
11
|
+
# The RSA modulus, a positive integer.
|
12
|
+
#
|
13
|
+
# @return [Integer]
|
14
|
+
attr_reader :modulus
|
15
|
+
alias_method :n, :modulus
|
16
|
+
|
17
|
+
##
|
18
|
+
# The RSA public or private exponent, a positive integer.
|
19
|
+
#
|
20
|
+
# @return [Integer]
|
21
|
+
attr_reader :exponent
|
22
|
+
alias_method :e, :exponent
|
23
|
+
alias_method :d, :exponent
|
24
|
+
|
25
|
+
##
|
26
|
+
# Initializes a new key.
|
27
|
+
#
|
28
|
+
# @param [Integer, #to_i] modulus
|
29
|
+
# @param [Integer, #to_i] exponent
|
30
|
+
# @param [Hash{Symbol => Object}] options
|
31
|
+
def initialize(modulus, exponent, options = {})
|
32
|
+
@modulus = modulus.to_i
|
33
|
+
@exponent = exponent.to_i
|
34
|
+
@options = options.dup
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Returns `true` if this is a valid RSA key according to {RSA::PKCS1
|
39
|
+
# PKCS #1}.
|
40
|
+
#
|
41
|
+
# @return [Boolean]
|
42
|
+
def valid?
|
43
|
+
true # TODO: PKCS #1 v2.1, sections 3.1 and 3.2, pp. 6-7.
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns a two-element array containing the modulus and exponent.
|
48
|
+
#
|
49
|
+
# @return [Array]
|
50
|
+
def to_a
|
51
|
+
[modulus, exponent]
|
52
|
+
end
|
53
|
+
end # class Key
|
54
|
+
end # module RSA
|
data/lib/rsa/key_pair.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module RSA
|
2
|
+
##
|
3
|
+
# An RSA key pair.
|
4
|
+
#
|
5
|
+
# Refer to PKCS #1 v2.1, section 3, pp. 6-8.
|
6
|
+
#
|
7
|
+
# @see http://www.rsa.com/rsalabs/node.asp?id=2125
|
8
|
+
# @see http://en.wikipedia.org/wiki/Public-key_cryptography
|
9
|
+
class KeyPair
|
10
|
+
##
|
11
|
+
# The RSA private key.
|
12
|
+
#
|
13
|
+
# @return [Key]
|
14
|
+
attr_reader :private_key
|
15
|
+
alias_method :private, :private_key
|
16
|
+
|
17
|
+
##
|
18
|
+
# The RSA public key.
|
19
|
+
#
|
20
|
+
# @return [Key]
|
21
|
+
attr_reader :public_key
|
22
|
+
alias_method :public, :public_key
|
23
|
+
|
24
|
+
##
|
25
|
+
# Initializes a new key pair.
|
26
|
+
#
|
27
|
+
# @param [Key] private_key
|
28
|
+
# @param [Key] public_key
|
29
|
+
# @param [Hash{Symbol => Object}] options
|
30
|
+
def initialize(private_key, public_key, options = {})
|
31
|
+
@private_key = private_key
|
32
|
+
@public_key = public_key
|
33
|
+
@options = options.dup
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Returns `true` if this key pair contains a private key.
|
38
|
+
#
|
39
|
+
# @return [Boolean]
|
40
|
+
def private_key?
|
41
|
+
!!private_key
|
42
|
+
end
|
43
|
+
alias_method :private?, :private_key? # for OpenSSL compatibility
|
44
|
+
|
45
|
+
##
|
46
|
+
# Returns `true` if this key pair contains a public key.
|
47
|
+
#
|
48
|
+
# @return [Boolean]
|
49
|
+
def public_key?
|
50
|
+
!!public_key
|
51
|
+
end
|
52
|
+
alias_method :public?, :public_key? # for OpenSSL compatibility
|
53
|
+
|
54
|
+
##
|
55
|
+
# Returns `true` if this is a valid RSA key pair according to
|
56
|
+
# {RSA::PKCS1 PKCS #1}.
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
# @see Key#valid?
|
60
|
+
def valid?
|
61
|
+
private_key.valid? && public_key.valid?
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Returns the byte size of this key pair.
|
66
|
+
#
|
67
|
+
# @return [Integer]
|
68
|
+
def bytesize
|
69
|
+
Math.log256(modulus).ceil
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Returns the bit size of this key pair.
|
74
|
+
#
|
75
|
+
# @return [Integer]
|
76
|
+
def bitsize
|
77
|
+
Math.log2(modulus).ceil
|
78
|
+
end
|
79
|
+
alias_method :size, :bitsize
|
80
|
+
|
81
|
+
##
|
82
|
+
# Returns the RSA modulus for this key pair.
|
83
|
+
#
|
84
|
+
# @return [Integer]
|
85
|
+
def modulus
|
86
|
+
private_key ? private_key.modulus : public_key.modulus
|
87
|
+
end
|
88
|
+
alias_method :n, :modulus
|
89
|
+
|
90
|
+
##
|
91
|
+
# Encrypts the given `plaintext` using the public key from this key
|
92
|
+
# pair.
|
93
|
+
#
|
94
|
+
# @param [Integer, String, IO] plaintext
|
95
|
+
# @param [Hash{Symbol => Object}] options
|
96
|
+
# @option options [Symbol, #to_sym] :padding (nil)
|
97
|
+
# @return [Integer]
|
98
|
+
def encrypt(plaintext, options = {})
|
99
|
+
PKCS1.rsaep(public_key, convert_to_integer(plaintext))
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Decrypts the given `ciphertext` using the private key from this key
|
104
|
+
# pair.
|
105
|
+
#
|
106
|
+
# @param [Integer, String, IO] ciphertext
|
107
|
+
# @param [Hash{Symbol => Object}] options
|
108
|
+
# @option options [Symbol, #to_sym] :padding (nil)
|
109
|
+
# @return [Integer]
|
110
|
+
def decrypt(ciphertext, options = {})
|
111
|
+
PKCS1.rsadp(private_key, convert_to_integer(ciphertext))
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Signs the given `plaintext` using the private key from this key pair.
|
116
|
+
#
|
117
|
+
# @param [Integer, String, IO] plaintext
|
118
|
+
# @param [Hash{Symbol => Object}] options
|
119
|
+
# @option options [Symbol, #to_sym] :padding (nil)
|
120
|
+
# @return [Integer]
|
121
|
+
def sign(plaintext, options = {})
|
122
|
+
PKCS1.rsasp1(private_key, convert_to_integer(plaintext))
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Verifies the given `signature` using the public key from this key
|
127
|
+
# pair.
|
128
|
+
#
|
129
|
+
# @param [Integer, String, IO] signature
|
130
|
+
# @param [Integer, String, IO] plaintext
|
131
|
+
# @param [Hash{Symbol => Object}] options
|
132
|
+
# @option options [Symbol, #to_sym] :padding (nil)
|
133
|
+
# @return [Boolean]
|
134
|
+
def verify(signature, plaintext, options = {})
|
135
|
+
PKCS1.rsavp1(public_key, convert_to_integer(signature)).eql?(convert_to_integer(plaintext))
|
136
|
+
end
|
137
|
+
|
138
|
+
protected
|
139
|
+
|
140
|
+
##
|
141
|
+
# Converts the given `input` to an integer suitable for use with RSA
|
142
|
+
# primitives.
|
143
|
+
#
|
144
|
+
# @param [Integer, String, IO] input
|
145
|
+
# @return [Integer]
|
146
|
+
def convert_to_integer(input)
|
147
|
+
case input
|
148
|
+
when Integer then input
|
149
|
+
when String then PKCS1.os2ip(input)
|
150
|
+
when IO, StringIO then PKCS1.os2ip(input.read)
|
151
|
+
else raise ArgumentError, input.inspect # FIXME
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end # class KeyPair
|
155
|
+
end # module RSA
|
data/lib/rsa/math.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module RSA
|
2
|
+
##
|
3
|
+
# Mathematical helper functions for RSA.
|
4
|
+
module Math
|
5
|
+
extend ::Math
|
6
|
+
|
7
|
+
##
|
8
|
+
# Performs a primality test on the integer `n`, returning `true` if it
|
9
|
+
# is a prime.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# 1.upto(10).select { |n| RSA::Math.prime?(n) } #=> [2, 3, 5, 7]
|
13
|
+
#
|
14
|
+
# @param [Integer] n
|
15
|
+
# @return [Boolean]
|
16
|
+
# @see http://en.wikipedia.org/wiki/Primality_test
|
17
|
+
# @see http://ruby-doc.org/core-1.9/classes/Prime.html
|
18
|
+
def self.prime?(n)
|
19
|
+
if n.respond_to?(:prime?)
|
20
|
+
n.prime?
|
21
|
+
else
|
22
|
+
require 'prime' unless defined?(Prime) # Ruby 1.9+ only
|
23
|
+
Prime.prime?(n)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Performs modular exponentiation in a memory-efficient manner.
|
29
|
+
#
|
30
|
+
# This is equivalent to `base**exponent % modulus` but much faster for
|
31
|
+
# large exponents.
|
32
|
+
#
|
33
|
+
# This is presently a semi-naive implementation. Don't rely on it for
|
34
|
+
# very large exponents.
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# RSA::Math.modpow(5, 3, 13) #=> 8
|
38
|
+
# RSA::Math.modpow(4, 13, 497) #=> 445
|
39
|
+
#
|
40
|
+
# @param [Integer] base
|
41
|
+
# @param [Integer] exponent
|
42
|
+
# @param [Integer] modulus
|
43
|
+
# @return [Integer]
|
44
|
+
# @see http://en.wikipedia.org/wiki/Modular_exponentiation
|
45
|
+
def self.modpow(base, exponent, modulus)
|
46
|
+
1.upto(exponent).inject(1) do |c, e|
|
47
|
+
(c * base) % modulus
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the Euler totient for the positive integer `n`.
|
53
|
+
#
|
54
|
+
# This is presently a very naive implementation. Don't rely on it for
|
55
|
+
# anything but very small values of `n`.
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# (1..5).map { |n| RSA::Math.phi(n) } #=> [1, 1, 2, 2, 4]
|
59
|
+
#
|
60
|
+
# @param [Integer] n
|
61
|
+
# @return [Integer]
|
62
|
+
# @see http://en.wikipedia.org/wiki/Euler's_totient_function
|
63
|
+
# @see http://mathworld.wolfram.com/TotientFunction.html
|
64
|
+
def self.phi(n)
|
65
|
+
1 + (2...n).count { |i| i.gcd(n).eql?(1) }
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Returns the binary logarithm of `n`.
|
70
|
+
#
|
71
|
+
# @param [Integer] n
|
72
|
+
# @return [Float]
|
73
|
+
# @see http://en.wikipedia.org/wiki/Binary_logarithm
|
74
|
+
def self.log2(n)
|
75
|
+
::Math.log2(n)
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Returns the base-256 logarithm of `n`.
|
80
|
+
#
|
81
|
+
# @param [Integer] n
|
82
|
+
# @return [Float]
|
83
|
+
# @see http://en.wikipedia.org/wiki/Logarithm
|
84
|
+
def self.log256(n)
|
85
|
+
::Math.log(n, 256)
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Returns the natural logarithm of `n`. If the optional argument `b` is
|
90
|
+
# given, it will be used as the base of the logarithm.
|
91
|
+
#
|
92
|
+
# @param [Integer] n
|
93
|
+
# @param [Integer] b
|
94
|
+
# @return [Float]
|
95
|
+
# @see http://en.wikipedia.org/wiki/Natural_logarithm
|
96
|
+
def self.log(n, b = nil)
|
97
|
+
b ? ::Math.log(n, b) : ::Math.log(n)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/rsa/openssl.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module RSA
|
2
|
+
module OpenSSL
|
3
|
+
# TODO
|
4
|
+
end # module OpenSSL
|
5
|
+
|
6
|
+
class KeyPair
|
7
|
+
##
|
8
|
+
# Generates a new RSA key pair of length `bits`.
|
9
|
+
#
|
10
|
+
# By default, the public exponent will be 65537 (0x10001) as recommended
|
11
|
+
# by {RSA::PKCS1 PKCS #1}.
|
12
|
+
#
|
13
|
+
# @param [Integer, #to_i] bits
|
14
|
+
# @param [Integer, #to_i] exponent
|
15
|
+
# @return [KeyPair]
|
16
|
+
def self.generate(bits, exponent = 65537)
|
17
|
+
pkey = ::OpenSSL::PKey::RSA.generate(bits.to_i, exponent.to_i)
|
18
|
+
n, d, e = pkey.n.to_i, pkey.d.to_i, pkey.e.to_i
|
19
|
+
self.new(Key.new(n, d), Key.new(n, e))
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Returns this key pair as an `OpenSSL::PKey::RSA` instance.
|
24
|
+
#
|
25
|
+
# @return [OpenSSL::PKey::RSA]
|
26
|
+
def to_openssl
|
27
|
+
@openssl_pkey ||= begin
|
28
|
+
pkey = ::OpenSSL::PKey::RSA.new
|
29
|
+
pkey.n = private_key.modulus if private_key?
|
30
|
+
pkey.e = private_key.exponent if private_key?
|
31
|
+
pkey.n ||= public_key.modulus if public_key?
|
32
|
+
pkey.d = public_key.exponent if public_key?
|
33
|
+
pkey
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end # class KeyPair
|
37
|
+
end # module RSA
|
data/lib/rsa/pkcs1.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module RSA
|
2
|
+
##
|
3
|
+
# Support for the PKCS #1 (aka RFC 3447) padding schemes.
|
4
|
+
#
|
5
|
+
# @see http://en.wikipedia.org/wiki/PKCS1
|
6
|
+
# @see http://tools.ietf.org/html/rfc3447
|
7
|
+
# @see http://www.rsa.com/rsalabs/node.asp?id=2125
|
8
|
+
module PKCS1
|
9
|
+
##
|
10
|
+
# Converts a nonnegative integer into an octet string of a specified
|
11
|
+
# length.
|
12
|
+
#
|
13
|
+
# This is the PKCS #1 I2OSP (Integer-to-Octet-String) primitive.
|
14
|
+
# Refer to PKCS #1 v2.1 pp. 8-9, section 4.1.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# RSA::PKCS1.i2osp(9_202_000, 2) #=> ArgumentError: integer too large
|
18
|
+
# RSA::PKCS1.i2osp(9_202_000, 3) #=> "\x8C\x69\x50"
|
19
|
+
# RSA::PKCS1.i2osp(9_202_000, 4) #=> "\x00\x8C\x69\x50"
|
20
|
+
#
|
21
|
+
# @param [Integer] x nonnegative integer to be converted
|
22
|
+
# @param [Integer] len intended length of the resulting octet string
|
23
|
+
# @return [String] octet string of length `len`
|
24
|
+
# @see http://tools.ietf.org/html/rfc3447#section-4.1
|
25
|
+
# @raise [ArgumentError] if `n` is greater than 256^len
|
26
|
+
def self.i2osp(x, len = Math.log256(x).ceil)
|
27
|
+
raise ArgumentError, "integer too large" if x >= 256**len
|
28
|
+
|
29
|
+
len.downto(1).inject(String.new) do |s, i|
|
30
|
+
b = (x & 0xFF).chr
|
31
|
+
x >>= 8
|
32
|
+
s = b + s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Converts an octet string into a nonnegative integer.
|
38
|
+
#
|
39
|
+
# This is the PKCS #1 OS2IP (Octet-String-to-Integer) primitive.
|
40
|
+
# Refer to PKCS #1 v2.1 p. 9, section 4.2.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# RSA::PKCS1.os2ip("\x8C\x69\x50") #=> 9_202_000
|
44
|
+
#
|
45
|
+
# @param [String] x octet string to be converted
|
46
|
+
# @return [Integer] nonnegative integer
|
47
|
+
# @see http://tools.ietf.org/html/rfc3447#section-4.2
|
48
|
+
def self.os2ip(x)
|
49
|
+
x.bytes.inject(0) { |n, b| (n << 8) + b }
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Produces a ciphertext representative from a message representative
|
54
|
+
# under the control of a public key.
|
55
|
+
#
|
56
|
+
# This is the PKCS #1 RSAEP encryption primitive.
|
57
|
+
# Refer to PKCS #1 v2.1 p. 10, section 5.1.1.
|
58
|
+
#
|
59
|
+
# @param [Key, #to_a] k RSA public key (`n`, `e`)
|
60
|
+
# @param [Integer] m message representative, an integer between 0 and `n` - 1
|
61
|
+
# @return [Integer] ciphertext representative, an integer between 0 and `n` - 1
|
62
|
+
# @raise [ArgumentError] if `m` is out of range
|
63
|
+
# @see http://tools.ietf.org/html/rfc3447#section-5.1.1
|
64
|
+
def self.rsaep(k, m)
|
65
|
+
n, e = k.to_a
|
66
|
+
raise ArgumentError, "message representative out of range" unless m >= 0 && m < n
|
67
|
+
c = Math.modpow(m, e, n)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Recovers the message representative from a ciphertext representative
|
72
|
+
# under the control of a private key.
|
73
|
+
#
|
74
|
+
# This is the PKCS #1 RSADP decryption primitive.
|
75
|
+
# Refer to PKCS #1 v2.1 pp. 10-11, section 5.1.2.
|
76
|
+
#
|
77
|
+
# @param [Key, #to_a] k RSA private key (`n`, `d`)
|
78
|
+
# @param [Integer] c ciphertext representative, an integer between 0 and `n` - 1
|
79
|
+
# @return [Integer] message representative, an integer between 0 and `n` - 1
|
80
|
+
# @raise [ArgumentError] if `c` is out of range
|
81
|
+
# @see http://tools.ietf.org/html/rfc3447#section-5.1.2
|
82
|
+
def self.rsadp(k, c)
|
83
|
+
n, d = k.to_a
|
84
|
+
raise ArgumentError, "ciphertext representative out of range" unless c >= 0 && c < n
|
85
|
+
m = Math.modpow(c, d, n)
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Produces a signature representative from a message representative
|
90
|
+
# under the control of a private key.
|
91
|
+
#
|
92
|
+
# This is the PKCS #1 RSASP1 signature primitive.
|
93
|
+
# Refer to PKCS #1 v2.1 pp. 12-13, section 5.2.1.
|
94
|
+
#
|
95
|
+
# @param [Key, #to_a] k RSA private key (`n`, `d`)
|
96
|
+
# @param [Integer] m message representative, an integer between 0 and `n` - 1
|
97
|
+
# @return [Integer] signature representative, an integer between 0 and `n` - 1
|
98
|
+
# @raise [ArgumentError] if `m` is out of range
|
99
|
+
# @see http://tools.ietf.org/html/rfc3447#section-5.2.1
|
100
|
+
def self.rsasp1(k, m)
|
101
|
+
n, d = k.to_a
|
102
|
+
raise ArgumentError, "message representative out of range" unless m >= 0 && m < n
|
103
|
+
s = Math.modpow(m, d, n)
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Recovers the message representative from a signature representative
|
108
|
+
# under the control of a public key.
|
109
|
+
#
|
110
|
+
# This is the PKCS #1 RSAVP1 verification primitive.
|
111
|
+
# Refer to PKCS #1 v2.1 p. 13, section 5.2.2.
|
112
|
+
#
|
113
|
+
# @param [Key, #to_a] k RSA public key (`n`, `e`)
|
114
|
+
# @param [Integer] s signature representative, an integer between 0 and `n` - 1
|
115
|
+
# @return [Integer] message representative, an integer between 0 and `n` - 1
|
116
|
+
# @raise [ArgumentError] if `s` is out of range
|
117
|
+
# @see http://tools.ietf.org/html/rfc3447#section-5.2.2
|
118
|
+
def self.rsavp1(k, s)
|
119
|
+
n, e = k.to_a
|
120
|
+
raise ArgumentError, "signature representative out of range" unless s >= 0 && s < n
|
121
|
+
m = Math.modpow(s, e, n)
|
122
|
+
end
|
123
|
+
end # module PKCS1
|
124
|
+
end # module RSA
|
data/lib/rsa/version.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RSA
|
2
|
+
module VERSION
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 1
|
5
|
+
TINY = 0
|
6
|
+
EXTRA = nil
|
7
|
+
|
8
|
+
STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
|
9
|
+
|
10
|
+
##
|
11
|
+
# @return [String]
|
12
|
+
def self.to_s() STRING end
|
13
|
+
|
14
|
+
##
|
15
|
+
# @return [String]
|
16
|
+
def self.to_str() STRING end
|
17
|
+
|
18
|
+
##
|
19
|
+
# @return [Array(Integer, Integer, Integer)]
|
20
|
+
def self.to_a() [MAJOR, MINOR, TINY] end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rsa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Arto Bendiken
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-06 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: yard
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 6
|
30
|
+
- 0
|
31
|
+
version: 0.6.0
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 3
|
44
|
+
- 0
|
45
|
+
version: 1.3.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: RSA.rb is a pure-Ruby implementation of the RSA encryption algorithm and the PKCS#1 cryptography standard.
|
49
|
+
email: arto.bendiken@gmail.com
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files: []
|
55
|
+
|
56
|
+
files:
|
57
|
+
- AUTHORS
|
58
|
+
- CREDITS
|
59
|
+
- README
|
60
|
+
- UNLICENSE
|
61
|
+
- VERSION
|
62
|
+
- lib/rsa/key.rb
|
63
|
+
- lib/rsa/key_pair.rb
|
64
|
+
- lib/rsa/math.rb
|
65
|
+
- lib/rsa/openssl.rb
|
66
|
+
- lib/rsa/pkcs1.rb
|
67
|
+
- lib/rsa/version.rb
|
68
|
+
- lib/rsa.rb
|
69
|
+
has_rdoc: false
|
70
|
+
homepage: http://rsa.rubyforge.org/
|
71
|
+
licenses:
|
72
|
+
- Public Domain
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 1
|
84
|
+
- 8
|
85
|
+
- 1
|
86
|
+
version: 1.8.1
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
requirements: []
|
95
|
+
|
96
|
+
rubyforge_project: rsa
|
97
|
+
rubygems_version: 1.3.6
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: RSA encryption for Ruby.
|
101
|
+
test_files: []
|
102
|
+
|