rsa-g 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 463d0dbc0338873b4d2aa01faab3eef89da7c99b
4
+ data.tar.gz: 2858960e94ac616e97bdd85763add76e7bc86b35
5
+ SHA512:
6
+ metadata.gz: e35f2fb15ea89dd07979a5a01ee665e51631e496952e640672ecbf700066a10541abca47a25dac1cacf26e9d77893e799bb1d3188c5aad8c989ecb31cc9cfb19
7
+ data.tar.gz: f1e482f1acabe397329ab2440e50d8ade9b20377c9ae5e26984400bf79257b9a5a0f8bb0310a4ba5de89bb46a599832c5c262eaf7225178d2cdd9c0a07c08e85
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ Gabriel Vian
data/CREDITS ADDED
File without changes
data/README ADDED
@@ -0,0 +1 @@
1
+ README.md
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
+ 1.0.0
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
@@ -0,0 +1,241 @@
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
+ # Returns a hash table representation of this key pair.
92
+ #
93
+ # @example
94
+ # key_pair.to_hash #=> {:n => ..., :d => ..., :e => ...}
95
+ #
96
+ # @return [Hash]
97
+ def to_hash
98
+ {:n => modulus, :d => private_key ? private_key.exponent : nil, :e => public_key ? public_key.exponent : nil}
99
+ end
100
+
101
+ ##
102
+ # Encrypts the given `plaintext` using the public key from this key
103
+ # pair.
104
+ #
105
+ # @overload encrypt(plaintext, options = {})
106
+ # @param [Integer] plaintext
107
+ # @param [Hash{Symbol => Object}] options
108
+ # @return [Integer]
109
+ #
110
+ # @overload encrypt(plaintext, options = {})
111
+ # @param [String, IO, StringIO] plaintext
112
+ # @param [Hash{Symbol => Object}] options
113
+ # @return [String]
114
+ #
115
+ # @param [Object] plaintext
116
+ # @param [Hash{Symbol => Object}] options
117
+ # @option options [Symbol, #to_sym] :padding (nil)
118
+ def encrypt(plaintext, options = {})
119
+ case plaintext
120
+ when Integer then encrypt_integer(plaintext, options)
121
+ when String then PKCS1.i2osp(encrypt_integer(PKCS1.os2ip(plaintext), options))
122
+ when StringIO, IO then PKCS1.i2osp(encrypt_integer(PKCS1.os2ip(plaintext.read), options))
123
+ else raise ArgumentError, plaintext.inspect # FIXME
124
+ end
125
+ end
126
+
127
+ ##
128
+ # Decrypts the given `ciphertext` using the private key from this key
129
+ # pair.
130
+ #
131
+ # @overload decrypt(ciphertext, options = {})
132
+ # @param [Integer] ciphertext
133
+ # @param [Hash{Symbol => Object}] options
134
+ # @return [Integer]
135
+ #
136
+ # @overload decrypt(ciphertext, options = {})
137
+ # @param [String, IO, StringIO] ciphertext
138
+ # @param [Hash{Symbol => Object}] options
139
+ # @return [String]
140
+ #
141
+ # @param [Object] ciphertext
142
+ # @param [Hash{Symbol => Object}] options
143
+ # @option options [Symbol, #to_sym] :padding (nil)
144
+ def decrypt(ciphertext, options = {})
145
+ case ciphertext
146
+ when Integer then decrypt_integer(ciphertext, options)
147
+ when String then PKCS1.i2osp(decrypt_integer(PKCS1.os2ip(ciphertext), options))
148
+ when StringIO, IO then PKCS1.i2osp(decrypt_integer(PKCS1.os2ip(ciphertext.read), options))
149
+ else raise ArgumentError, ciphertext.inspect # FIXME
150
+ end
151
+ end
152
+
153
+ ##
154
+ # Signs the given `plaintext` using the private key from this key pair.
155
+ #
156
+ # @overload sign(plaintext, options = {})
157
+ # @param [Integer] plaintext
158
+ # @param [Hash{Symbol => Object}] options
159
+ # @return [Integer]
160
+ #
161
+ # @overload sign(plaintext, options = {})
162
+ # @param [String, IO, StringIO] plaintext
163
+ # @param [Hash{Symbol => Object}] options
164
+ # @return [String]
165
+ #
166
+ # @param [Object] plaintext
167
+ # @param [Hash{Symbol => Object}] options
168
+ # @option options [Symbol, #to_sym] :padding (nil)
169
+ def sign(plaintext, options = {})
170
+ case plaintext
171
+ when Integer then sign_integer(plaintext, options)
172
+ when String then PKCS1.i2osp(sign_integer(PKCS1.os2ip(plaintext), options))
173
+ when StringIO, IO then PKCS1.i2osp(sign_integer(PKCS1.os2ip(plaintext.read), options))
174
+ else raise ArgumentError, plaintext.inspect # FIXME
175
+ end
176
+ end
177
+
178
+ ##
179
+ # Verifies the given `signature` using the public key from this key
180
+ # pair.
181
+ #
182
+ # @overload verify(signature, plaintext, options = {})
183
+ # @param [Integer] signature
184
+ # @param [Integer] plaintext
185
+ # @param [Hash{Symbol => Object}] options
186
+ # @return [Boolean]
187
+ #
188
+ # @overload verify(signature, plaintext, options = {})
189
+ # @param [String, IO, StringIO] signature
190
+ # @param [String, IO, StringIO] plaintext
191
+ # @param [Hash{Symbol => Object}] options
192
+ # @return [Boolean]
193
+ #
194
+ # @param [Object] signature
195
+ # @param [Object] plaintext
196
+ # @param [Hash{Symbol => Object}] options
197
+ # @option options [Symbol, #to_sym] :padding (nil)
198
+ # @return [Boolean]
199
+ def verify(signature, plaintext, options = {})
200
+ signature = case signature
201
+ when Integer then signature
202
+ when String then PKCS1.os2ip(signature)
203
+ when StringIO, IO then PKCS1.os2ip(signature.read)
204
+ else raise ArgumentError, signature.inspect # FIXME
205
+ end
206
+ plaintext = case plaintext
207
+ when Integer then plaintext
208
+ when String then PKCS1.os2ip(plaintext)
209
+ when StringIO, IO then PKCS1.os2ip(plaintext.read)
210
+ else raise ArgumentError, plaintext.inspect # FIXME
211
+ end
212
+ verify_integer(signature, plaintext, options)
213
+ end
214
+
215
+ protected
216
+
217
+ ##
218
+ # @private
219
+ def encrypt_integer(plaintext, options = {})
220
+ PKCS1.rsaep(public_key, plaintext)
221
+ end
222
+
223
+ ##
224
+ # @private
225
+ def decrypt_integer(ciphertext, options = {})
226
+ PKCS1.rsadp(private_key, ciphertext)
227
+ end
228
+
229
+ ##
230
+ # @private
231
+ def sign_integer(plaintext, options = {})
232
+ PKCS1.rsasp1(private_key, plaintext)
233
+ end
234
+
235
+ ##
236
+ # @private
237
+ def verify_integer(signature, plaintext, options = {})
238
+ PKCS1.rsavp1(public_key, signature).eql?(plaintext)
239
+ end
240
+ end # class KeyPair
241
+ end # module RSA
data/lib/rsa/math.rb ADDED
@@ -0,0 +1,277 @@
1
+ module RSA
2
+ ##
3
+ # Mathematical helper functions for RSA.
4
+ module Math
5
+ extend ::Math
6
+
7
+ class ArithmeticError < ArgumentError; end
8
+
9
+ ##
10
+ # Yields an infinite pseudo-prime number sequence.
11
+ #
12
+ # This is a pseudo-prime generator that simply yields the initial values
13
+ # 2 and 3, followed by all positive integers that are not divisible by 2
14
+ # or 3.
15
+ #
16
+ # It works identically to `Prime::Generator23`, the Ruby 1.9 standard
17
+ # library's default pseudo-prime generator implementation.
18
+ #
19
+ # @example
20
+ # RSA::Math.primes.take(5) #=> [2, 3, 5, 7, 11]
21
+ #
22
+ # @yield [p] each pseudo-prime number
23
+ # @yieldparam [Integer] p a pseudo-prime number
24
+ # @return [Enumerator] yielding pseudo-primes
25
+ # @see http://ruby-doc.org/core-1.9/classes/Prime.html
26
+ def self.primes(&block)
27
+ if block_given?
28
+ yield 2; yield 3; yield 5
29
+ prime, step = 5, 4
30
+ loop { yield prime += (step = 6 - step) }
31
+ end
32
+ enum_for(:primes)
33
+ end
34
+
35
+ ##
36
+ # Yields the prime factorization of the nonzero integer `n`.
37
+ #
38
+ # @example
39
+ # RSA::Math.factorize(12).to_a #=> [[2, 2], [3, 1]]
40
+ #
41
+ # @param [Integer] n a nonzero integer
42
+ # @yield [p, e] each prime factor
43
+ # @yieldparam [Integer] p the prime factor base
44
+ # @yieldparam [Integer] e the prime factor exponent
45
+ # @return [Enumerator]
46
+ # @raise [ZeroDivisionError] if `n` is zero
47
+ # @see http://ruby-doc.org/core-1.9/classes/Prime.html
48
+ def self.factorize(n, &block)
49
+ raise ZeroDivisionError if n.zero?
50
+ if block_given?
51
+ n = n.abs if n < 0
52
+ primes.find do |p|
53
+ e = 0
54
+ while (q, r = n.divmod(p); r.zero?)
55
+ n, e = q, e + 1
56
+ end
57
+ yield p, e unless e.zero?
58
+ n <= p
59
+ end
60
+ yield n, 1 if n > 1
61
+ end
62
+ enum_for(:factorize, n)
63
+ end
64
+
65
+ ##
66
+ # Performs a primality test on the integer `n`, returning `true` if it
67
+ # is a prime.
68
+ #
69
+ # @example
70
+ # 1.upto(10).select { |n| RSA::Math.prime?(n) } #=> [2, 3, 5, 7]
71
+ #
72
+ # @param [Integer] n an integer
73
+ # @return [Boolean] `true` if `n` is a prime number, `false` otherwise
74
+ # @see http://en.wikipedia.org/wiki/Primality_test
75
+ # @see http://ruby-doc.org/core-1.9/classes/Prime.html
76
+ def self.prime?(n)
77
+ case
78
+ when n < 0 then prime?(n.abs)
79
+ when n < 2 then false
80
+ else primes do |p|
81
+ q, r = n.divmod(p)
82
+ return true if q < p
83
+ return false if r.zero?
84
+ end
85
+ end
86
+ end
87
+
88
+ ##
89
+ # Returns `true` if the integer `a` is coprime (relatively prime) to
90
+ # integer `b`.
91
+ #
92
+ # @example
93
+ # RSA::Math.coprime?(6, 35) #=> true
94
+ # RSA::Math.coprime?(6, 27) #=> false
95
+ #
96
+ # @param [Integer] a an integer
97
+ # @param [Integer] b an integer
98
+ # @return [Boolean] `true` if `a` and `b` are coprime, `false` otherwise
99
+ # @see http://en.wikipedia.org/wiki/Coprime
100
+ # @see http://mathworld.wolfram.com/RelativelyPrime.html
101
+ def self.coprime?(a, b)
102
+ egcd = self.egcd(a, b)
103
+ (a*egcd[0] + b*egcd[1]).eql?(1)
104
+ end
105
+
106
+ ##
107
+ # Returns the greatest common divisor (GCD) of the two integers `a` and
108
+ # `b`. The GCD is the largest positive integer that divides both numbers
109
+ # without a remainder.
110
+ #
111
+ # @example
112
+ # RSA::Math.gcd(3, 5) #=> 1
113
+ # RSA::Math.gcd(8, 12) #=> 4
114
+ # RSA::Math.gcd(12, 60) #=> 12
115
+ # RSA::Math.gcd(90, 12) #=> 6
116
+ #
117
+ # @param [Integer] a an integer
118
+ # @param [Integer] b an integer
119
+ # @return [Integer] the greatest common divisor of `a` and `b`
120
+ # @see http://en.wikipedia.org/wiki/Greatest_common_divisor
121
+ # @see http://mathworld.wolfram.com/GreatestCommonDivisor.html
122
+ def self.gcd(a, b)
123
+ a.gcd(b)
124
+ end
125
+
126
+ ##
127
+ # Returns the Bezout coefficients of the two nonzero integers `a` and
128
+ # `b` using the extended Euclidean algorithm.
129
+ #
130
+ # @example
131
+ # RSA::Math.egcd(120, 23) #=> [-9, 47]
132
+ # RSA::Math.egcd(421, 111) #=> [-29, 110]
133
+ # RSA::Math.egcd(93, 219) #=> [33, -14]
134
+ # RSA::Math.egcd(4864, 3458) #=> [32, -45]
135
+ #
136
+ # @param [Integer] a a nonzero integer
137
+ # @param [Integer] b a nonzero integer
138
+ # @return [Array(Integer, Integer)] the Bezout coefficients `x` and `y`
139
+ # @raise [ZeroDivisionError] if `a` or `b` is zero
140
+ # @see http://en.wikipedia.org/wiki/B%C3%A9zout's_identity
141
+ # @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
142
+ # @see http://mathworld.wolfram.com/ExtendedGreatestCommonDivisor.html
143
+ def self.egcd(a, b)
144
+ if a.modulo(b).zero?
145
+ [0, 1]
146
+ else
147
+ x, y = egcd(b, a.modulo(b))
148
+ [y, x - y * a.div(b)]
149
+ end
150
+ end
151
+
152
+ ##
153
+ # Returns the modular multiplicative inverse of the integer `b` modulo
154
+ # `m`, where `b <= m`.
155
+ #
156
+ # The running time of the used algorithm, the extended Euclidean
157
+ # algorithm, is on the order of O(log2 _m_).
158
+ #
159
+ # @example
160
+ # RSA::Math.modinv(3, 11) #=> 4
161
+ # RSA::Math.modinv(6, 35) #=> 6
162
+ # RSA::Math.modinv(-6, 35) #=> 29
163
+ # RSA::Math.modinv(6, 36) #=> ArithmeticError
164
+ #
165
+ # @param [Integer] b
166
+ # @param [Integer] m the modulus
167
+ # @return [Integer] the modular multiplicative inverse
168
+ # @raise [ArithmeticError] if `m` <= 0, or if `b` not coprime to `m`
169
+ # @see http://en.wikipedia.org/wiki/Modular_multiplicative_inverse
170
+ # @see http://mathworld.wolfram.com/ModularInverse.html
171
+ def self.modinv(b, m)
172
+ if m > 0 && coprime?(b, m)
173
+ egcd(b, m).first.modulo(m)
174
+ else
175
+ raise ArithmeticError, "modulus #{m} is not positive" if m <= 0
176
+ raise ArithmeticError, "#{b} is not coprime to #{m}"
177
+ end
178
+ end
179
+
180
+ ##
181
+ # Performs modular exponentiation in a memory-efficient manner.
182
+ #
183
+ # This is equivalent to `base**exponent % modulus` but much faster for
184
+ # large exponents.
185
+ #
186
+ # The running time of the used algorithm, the right-to-left binary
187
+ # method, is on the order of O(log _exponent_).
188
+ #
189
+ # @example
190
+ # RSA::Math.modpow(5, 3, 13) #=> 8
191
+ # RSA::Math.modpow(4, 13, 497) #=> 445
192
+ #
193
+ # @param [Integer] base the base
194
+ # @param [Integer] exponent the exponent
195
+ # @param [Integer] modulus the modulus
196
+ # @return [Integer] the result
197
+ # @see http://en.wikipedia.org/wiki/Modular_exponentiation
198
+ def self.modpow(base, exponent, modulus)
199
+ result = 1
200
+ while exponent > 0
201
+ result = (base * result) % modulus unless (exponent & 1).zero?
202
+ base = (base * base) % modulus
203
+ exponent >>= 1
204
+ end
205
+ result
206
+ end
207
+
208
+ ONE = BigDecimal('1')
209
+
210
+ ##
211
+ # Returns the Euler totient for the positive integer `n`.
212
+ #
213
+ # @example
214
+ # (1..5).map { |n| RSA::Math.phi(n) } #=> [1, 1, 2, 2, 4]
215
+ #
216
+ # @param [Integer] n a positive integer, or zero
217
+ # @return [Integer] the Euler totient of `n`
218
+ # @raise [ArgumentError] if `n` < 0
219
+ # @see http://en.wikipedia.org/wiki/Euler's_totient_function
220
+ # @see http://mathworld.wolfram.com/TotientFunction.html
221
+ def self.phi(n)
222
+ case
223
+ when n < 0 then raise ArgumentError, "expected a positive integer, but got #{n}"
224
+ when n < 2 then 1 # by convention
225
+ when prime?(n) then n - 1
226
+ else factorize(n).inject(n) { |product, (p, e)| product * (ONE - (ONE / BigDecimal(p.to_s))) }.round.to_i
227
+ end
228
+ end
229
+
230
+ ##
231
+ # Returns the binary logarithm of `n`.
232
+ #
233
+ # @example
234
+ # RSA::Math.log2(16) #=> 4.0
235
+ # RSA::Math.log2(1024) #=> 10.0
236
+ #
237
+ # @param [Integer] n a positive integer
238
+ # @return [Float] the logarithm
239
+ # @raise [Errno::EDOM] if `n` < 1
240
+ # @see http://en.wikipedia.org/wiki/Binary_logarithm
241
+ def self.log2(n)
242
+ ::Math.log2(n)
243
+ end
244
+
245
+ ##
246
+ # Returns the base-256 logarithm of `n`.
247
+ #
248
+ # @example
249
+ # RSA::Math.log256(16) #=> 0.5
250
+ # RSA::Math.log256(1024) #=> 1.25
251
+ #
252
+ # @param [Integer] n a positive integer
253
+ # @return [Float] the logarithm
254
+ # @raise [Errno::EDOM] if `n` < 1
255
+ # @see http://en.wikipedia.org/wiki/Logarithm
256
+ def self.log256(n)
257
+ ::Math.log(n, 256)
258
+ end
259
+
260
+ ##
261
+ # Returns the natural logarithm of `n`. If the optional argument `b` is
262
+ # given, it will be used as the base of the logarithm.
263
+ #
264
+ # @example
265
+ # RSA::Math.log(16, 2) #=> 4.0
266
+ # RSA::Math.log(16, 256) #=> 0.5
267
+ #
268
+ # @param [Integer] n a positive integer
269
+ # @param [Integer] b a positive integer >= 2, or `nil`
270
+ # @return [Float] the logarithm
271
+ # @raise [Errno::EDOM] if `n` < 1, or if `b` < 2
272
+ # @see http://en.wikipedia.org/wiki/Natural_logarithm
273
+ def self.log(n, b = nil)
274
+ b ? ::Math.log(n, b) : ::Math.log(n)
275
+ end
276
+ end
277
+ end
@@ -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,130 @@
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 = nil)
27
+ raise ArgumentError, "integer too large" if len && x >= 256**len
28
+
29
+ StringIO.open do |buffer|
30
+ while x > 0
31
+ b = (x & 0xFF).chr
32
+ x >>= 8
33
+ buffer << b
34
+ end
35
+ s = buffer.string
36
+ s.force_encoding(Encoding::BINARY) if s.respond_to?(:force_encoding)
37
+ s.reverse!
38
+ s = len ? s.rjust(len, "\0") : s
39
+ end
40
+ end
41
+
42
+ ##
43
+ # Converts an octet string into a nonnegative integer.
44
+ #
45
+ # This is the PKCS #1 OS2IP (Octet-String-to-Integer) primitive.
46
+ # Refer to PKCS #1 v2.1 p. 9, section 4.2.
47
+ #
48
+ # @example
49
+ # RSA::PKCS1.os2ip("\x8C\x69\x50") #=> 9_202_000
50
+ #
51
+ # @param [String] x octet string to be converted
52
+ # @return [Integer] nonnegative integer
53
+ # @see http://tools.ietf.org/html/rfc3447#section-4.2
54
+ def self.os2ip(x)
55
+ x.bytes.inject(0) { |n, b| (n << 8) + b }
56
+ end
57
+
58
+ ##
59
+ # Produces a ciphertext representative from a message representative
60
+ # under the control of a public key.
61
+ #
62
+ # This is the PKCS #1 RSAEP encryption primitive.
63
+ # Refer to PKCS #1 v2.1 p. 10, section 5.1.1.
64
+ #
65
+ # @param [Key, #to_a] k RSA public key (`n`, `e`)
66
+ # @param [Integer] m message representative, an integer between 0 and `n` - 1
67
+ # @return [Integer] ciphertext representative, an integer between 0 and `n` - 1
68
+ # @raise [ArgumentError] if `m` is out of range
69
+ # @see http://tools.ietf.org/html/rfc3447#section-5.1.1
70
+ def self.rsaep(k, m)
71
+ n, e = k.to_a
72
+ raise ArgumentError, "message representative out of range" unless m >= 0 && m < n
73
+ c = Math.modpow(m, e, n)
74
+ end
75
+
76
+ ##
77
+ # Recovers the message representative from a ciphertext representative
78
+ # under the control of a private key.
79
+ #
80
+ # This is the PKCS #1 RSADP decryption primitive.
81
+ # Refer to PKCS #1 v2.1 pp. 10-11, section 5.1.2.
82
+ #
83
+ # @param [Key, #to_a] k RSA private key (`n`, `d`)
84
+ # @param [Integer] c ciphertext representative, an integer between 0 and `n` - 1
85
+ # @return [Integer] message representative, an integer between 0 and `n` - 1
86
+ # @raise [ArgumentError] if `c` is out of range
87
+ # @see http://tools.ietf.org/html/rfc3447#section-5.1.2
88
+ def self.rsadp(k, c)
89
+ n, d = k.to_a
90
+ raise ArgumentError, "ciphertext representative out of range" unless c >= 0 && c < n
91
+ m = Math.modpow(c, d, n)
92
+ end
93
+
94
+ ##
95
+ # Produces a signature representative from a message representative
96
+ # under the control of a private key.
97
+ #
98
+ # This is the PKCS #1 RSASP1 signature primitive.
99
+ # Refer to PKCS #1 v2.1 pp. 12-13, section 5.2.1.
100
+ #
101
+ # @param [Key, #to_a] k RSA private key (`n`, `d`)
102
+ # @param [Integer] m message representative, an integer between 0 and `n` - 1
103
+ # @return [Integer] signature representative, an integer between 0 and `n` - 1
104
+ # @raise [ArgumentError] if `m` is out of range
105
+ # @see http://tools.ietf.org/html/rfc3447#section-5.2.1
106
+ def self.rsasp1(k, m)
107
+ n, d = k.to_a
108
+ raise ArgumentError, "message representative out of range" unless m >= 0 && m < n
109
+ s = Math.modpow(m, d, n)
110
+ end
111
+
112
+ ##
113
+ # Recovers the message representative from a signature representative
114
+ # under the control of a public key.
115
+ #
116
+ # This is the PKCS #1 RSAVP1 verification primitive.
117
+ # Refer to PKCS #1 v2.1 p. 13, section 5.2.2.
118
+ #
119
+ # @param [Key, #to_a] k RSA public key (`n`, `e`)
120
+ # @param [Integer] s signature representative, an integer between 0 and `n` - 1
121
+ # @return [Integer] message representative, an integer between 0 and `n` - 1
122
+ # @raise [ArgumentError] if `s` is out of range
123
+ # @see http://tools.ietf.org/html/rfc3447#section-5.2.2
124
+ def self.rsavp1(k, s)
125
+ n, e = k.to_a
126
+ raise ArgumentError, "signature representative out of range" unless s >= 0 && s < n
127
+ m = Math.modpow(s, e, n)
128
+ end
129
+ end # module PKCS1
130
+ end # module RSA
@@ -0,0 +1,22 @@
1
+ module RSA
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 4
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
data/lib/rsa.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'bigdecimal' unless defined?(BigDecimal)
2
+ require 'stringio' unless defined?(StringIO)
3
+
4
+ if RUBY_VERSION < '1.9.1'
5
+ # @see http://rubygems.org/gems/backports
6
+ begin
7
+ require 'backports/1.9.1'
8
+ rescue LoadError
9
+ abort "RSA.rb requires Ruby 1.9.1 or the Backports gem (hint: `gem install backports')."
10
+ end
11
+ end
12
+
13
+ module RSA
14
+ autoload :Math, 'rsa/math'
15
+ autoload :PKCS1, 'rsa/pkcs1'
16
+ autoload :Key, 'rsa/key'
17
+ autoload :KeyPair, 'rsa/key_pair'
18
+ autoload :OpenSSL, 'rsa/openssl'
19
+ autoload :VERSION, 'rsa/version'
20
+ end
21
+
22
+ begin
23
+ require 'openssl'
24
+ require 'rsa/openssl'
25
+ rescue LoadError
26
+ # OpenSSL acceleration disabled.
27
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsa-g
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Vian
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.0
41
+ description: RSA.rb is a pure-Ruby implementation of the RSA encryption algorithm
42
+ and the PKCS#1 cryptography standard.
43
+ email:
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - AUTHORS
49
+ - CREDITS
50
+ - README
51
+ - UNLICENSE
52
+ - VERSION
53
+ - lib/rsa.rb
54
+ - lib/rsa/key.rb
55
+ - lib/rsa/key_pair.rb
56
+ - lib/rsa/math.rb
57
+ - lib/rsa/openssl.rb
58
+ - lib/rsa/pkcs1.rb
59
+ - lib/rsa/version.rb
60
+ homepage:
61
+ licenses:
62
+ - Unlicense
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.8.1
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project: rsa
80
+ rubygems_version: 2.6.14.1
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: RSA encryption for Ruby.
84
+ test_files: []