akero 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +3 -0
  3. data/.gitignore +0 -2
  4. data/.rubocop.yml +43 -0
  5. data/.travis.yml +3 -7
  6. data/Gemfile +1 -0
  7. data/Guardfile +4 -3
  8. data/Makefile +26 -0
  9. data/README.md +28 -10
  10. data/Rakefile +8 -17
  11. data/akero.gemspec +17 -10
  12. data/bin/akero +6 -0
  13. data/coverage/.last_run.json +5 -0
  14. data/coverage/.resultset.json +367 -0
  15. data/coverage/.resultset.json.lock +0 -0
  16. data/coverage/assets/0.10.0/application.css +799 -0
  17. data/coverage/assets/0.10.0/application.js +1707 -0
  18. data/coverage/assets/0.10.0/colorbox/border.png +0 -0
  19. data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  20. data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  21. data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  22. data/coverage/assets/0.10.0/favicon_green.png +0 -0
  23. data/coverage/assets/0.10.0/favicon_red.png +0 -0
  24. data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  25. data/coverage/assets/0.10.0/loading.gif +0 -0
  26. data/coverage/assets/0.10.0/magnify.png +0 -0
  27. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  28. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  29. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  30. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  31. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  32. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  33. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  34. data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  35. data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  36. data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  37. data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  38. data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  39. data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  40. data/coverage/assets/0.7.1/application.css +1110 -0
  41. data/coverage/assets/0.7.1/application.js +626 -0
  42. data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
  43. data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
  44. data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
  45. data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
  46. data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
  47. data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
  48. data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
  49. data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
  50. data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
  51. data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
  52. data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
  53. data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
  54. data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
  55. data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
  56. data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
  57. data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
  58. data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
  59. data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
  60. data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
  61. data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
  62. data/coverage/assets/0.7.1/favicon_green.png +0 -0
  63. data/coverage/assets/0.7.1/favicon_red.png +0 -0
  64. data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
  65. data/coverage/assets/0.7.1/loading.gif +0 -0
  66. data/coverage/assets/0.7.1/magnify.png +0 -0
  67. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  68. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  69. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  70. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  71. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  72. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  73. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  74. data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  75. data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
  76. data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  77. data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
  78. data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
  79. data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  80. data/coverage/index.html +2248 -0
  81. data/doc/Akero/Message.html +475 -0
  82. data/doc/Akero.html +1148 -0
  83. data/doc/_index.html +125 -0
  84. data/doc/class_list.html +53 -0
  85. data/doc/css/common.css +1 -0
  86. data/doc/css/full_list.css +57 -0
  87. data/doc/css/style.css +338 -0
  88. data/doc/file.README.html +186 -0
  89. data/doc/file_list.html +55 -0
  90. data/doc/frames.html +28 -0
  91. data/doc/index.html +186 -0
  92. data/doc/js/app.js +214 -0
  93. data/doc/js/full_list.js +173 -0
  94. data/doc/js/jquery.js +4 -0
  95. data/doc/method_list.html +148 -0
  96. data/doc/top-level-namespace.html +112 -0
  97. data/lib/akero/benchmark.rb +21 -20
  98. data/lib/akero/cli.rb +74 -0
  99. data/lib/akero/version.rb +2 -1
  100. data/lib/akero.rb +92 -90
  101. data/spec/akero_spec.rb +66 -65
  102. data/spec/spec_helper.rb +1 -0
  103. metadata +164 -52
data/lib/akero.rb CHANGED
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  # Copyright (c) 2012 moe@busyloop.net
2
- #
3
+ #
3
4
  # MIT License
4
- #
5
+ #
5
6
  # Permission is hereby granted, free of charge, to any person obtaining
6
7
  # a copy of this software and associated documentation files (the
7
8
  # "Software"), to deal in the Software without restriction, including
@@ -9,10 +10,10 @@
9
10
  # distribute, sublicense, and/or sell copies of the Software, and to
10
11
  # permit persons to whom the Software is furnished to do so, subject to
11
12
  # the following conditions:
12
- #
13
+ #
13
14
  # The above copyright notice and this permission notice shall be
14
15
  # included in all copies or substantial portions of the Software.
15
- #
16
+ #
16
17
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
18
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
19
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -21,15 +22,16 @@
21
22
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24
 
24
- require "akero/version"
25
+ require 'akero/version'
25
26
 
26
27
  require 'openssl'
27
28
  require 'base64'
28
29
 
29
30
  # Akero is an easy-to-use library for peer-to-peer public key cryptography.
30
31
  #
31
- # Tested on: MRI 1.8.7, MRI 1.9.2, MRI 1.9.3, RBX 1.8, RBX 1.9
32
- # (JRuby may be added in the future but is currently NOT supported)
32
+ # The only officially supported ruby runtime is MRI (latest version).
33
+ # Regardless, Akero is known to work on any recent ruby version except JRuby.
34
+ # Tested on: MRI 1.8.7, MRI 1.9.2, MRI 1.9.3, RBX 1.8, RBX 1.9, MRI 2.3.*, and more.
33
35
  class Akero
34
36
  # Akero::Message wraps a received message.
35
37
  class Message
@@ -40,7 +42,9 @@ class Akero
40
42
 
41
43
  # @private
42
44
  def initialize(body, signer_cert, type)
43
- @body, @signer_cert, @type = body, signer_cert, type
45
+ @body = body
46
+ @signer_cert = signer_cert
47
+ @type = type
44
48
  end
45
49
 
46
50
  # @private
@@ -62,25 +66,26 @@ class Akero
62
66
  end
63
67
  end
64
68
 
69
+ # Akero
65
70
  class Akero
66
- ERR_MSG_MALFORMED_ENV = "Malformed message: Could not parse envelope" # @private
67
- ERR_MSG_MALFORMED_BODY = "Malformed message: Could not parse body; POSSIBLE SPOOF ATTEMPT" # @private
68
- ERR_PKEY_CORRUPT = "Invalid private key (checksum mismatch)" # @private
69
- ERR_CERT_CORRUPT = "Invalid certificate" # @private
70
- ERR_INVALID_RECIPIENT = "Invalid recipient (must be a String)" # @private
71
- ERR_INVALID_RECIPIENT_CERT = "Invalid recipient (corrupt public key?)" # @private
72
- ERR_DECRYPT = "Could not decrypt message" # @private
73
- ERR_MSG_NOT_STRING_NOR_PKCS7 = "Message must be of type String or OpenSSL::PKCS7" # @private
74
- ERR_MSG_CORRUPT_CERT = "Malformed message: Embedded certificate could not be verified; POSSIBLE SPOOF ATTEMPT!" # @private
75
- ERR_MSG_TOO_MANY_SIGNERS = "Corrupt message: Zero or multiple signers, expected exactly 1; POSSIBLE SPOOF ATTEMPT" # @private
71
+ ERR_MSG_MALFORMED_ENV = 'Malformed message: Could not parse envelope' # @private
72
+ ERR_MSG_MALFORMED_BODY = 'Malformed message: Could not parse body; POSSIBLE SPOOF ATTEMPT' # @private
73
+ ERR_PKEY_CORRUPT = 'Invalid private key (checksum mismatch)' # @private
74
+ ERR_CERT_CORRUPT = 'Invalid certificate' # @private
75
+ ERR_INVALID_RECIPIENT = 'Invalid recipient (must be a String)' # @private
76
+ ERR_INVALID_RECIPIENT_CERT = 'Invalid recipient (corrupt public key?)' # @private
77
+ ERR_DECRYPT = 'Could not decrypt message' # @private
78
+ ERR_MSG_NOT_STRING_NOR_PKCS7 = 'Message must be of type String or OpenSSL::PKCS7' # @private
79
+ ERR_MSG_CORRUPT_CERT = 'Malformed message: Embedded certificate could not be verified; POSSIBLE SPOOF ATTEMPT!' # @private
80
+ ERR_MSG_TOO_MANY_SIGNERS = 'Corrupt message: Zero or multiple signers, expected exactly 1; POSSIBLE SPOOF ATTEMPT' # @private
76
81
 
77
82
  PKEY_HEADER = "-----BEGIN AKERO PRIVATE KEY-----\n" # @private
78
83
  PKEY_FOOTER = "-----END AKERO PRIVATE KEY-----\n" # @private
79
- PLATE_CERT = ['CERTIFICATE','AKERO PUBLIC KEY'] # @private
80
- PLATE_SIGNED = ['PKCS7', 'AKERO SIGNED MESSAGE'] # @private
81
- PLATE_CRYPTED = ['PKCS7', 'AKERO SECRET MESSAGE'] # @private
84
+ PLATE_CERT = ['CERTIFICATE', 'AKERO PUBLIC KEY'].freeze # @private
85
+ PLATE_SIGNED = ['PKCS7', 'AKERO SIGNED MESSAGE'].freeze # @private
86
+ PLATE_CRYPTED = ['PKCS7', 'AKERO SECRET MESSAGE'].freeze # @private
82
87
 
83
- DEFAULT_RSA_BITS = 2048
88
+ DEFAULT_RSA_BITS = 4096
84
89
  DEFAULT_DIGEST = OpenSSL::Digest::SHA512
85
90
 
86
91
  # Unique fingerprint of this Akero keypair.
@@ -104,26 +109,26 @@ class Akero
104
109
  # @param [Integer] rsa_bits RSA key length
105
110
  # @param [OpenSSL::Digest] digest Signature digest
106
111
  # @return [Akero] New Akero instance
107
- def initialize(rsa_bits=DEFAULT_RSA_BITS, digest=DEFAULT_DIGEST)
112
+ def initialize(rsa_bits = DEFAULT_RSA_BITS, digest = DEFAULT_DIGEST)
108
113
  @key, @cert = generate_keypair(rsa_bits, digest) unless rsa_bits.nil?
109
114
  end
110
115
 
111
116
  # Load an Akero identity.
112
- #
117
+ #
113
118
  # @example Load previously stored private key
114
119
  # Akero.load(File.read('/tmp/alice.akr'))
115
120
  #
116
121
  # @param [String] private_key Akero private key
117
122
  # @return [Akero] New Akero instance
118
123
  def self.load(private_key)
119
- inner = Base64.decode64(private_key[PKEY_HEADER.length..private_key.length-PKEY_FOOTER.length])
124
+ inner = Base64.decode64(private_key[PKEY_HEADER.length..private_key.length - PKEY_FOOTER.length])
120
125
  if inner[0..63] != OpenSSL::Digest::SHA512.new(inner[64..-1]).digest
121
- raise RuntimeError, ERR_PKEY_CORRUPT
126
+ raise ERR_PKEY_CORRUPT
122
127
  end
123
128
  cert_len = inner[64..65].unpack('S')[0]
124
129
  akero = Akero.new(nil)
125
- akero.instance_variable_set(:@cert, OpenSSL::X509::Certificate.new(inner[66..66+cert_len]))
126
- akero.instance_variable_set(:@key, OpenSSL::PKey::RSA.new(inner[66+cert_len..-1]))
130
+ akero.instance_variable_set(:@cert, OpenSSL::X509::Certificate.new(inner[66..66 + cert_len]))
131
+ akero.instance_variable_set(:@key, OpenSSL::PKey::RSA.new(inner[66 + cert_len..-1]))
127
132
  akero
128
133
  end
129
134
 
@@ -134,18 +139,18 @@ class Akero
134
139
  #
135
140
  # @return [String] Public key (ascii armored)
136
141
  def public_key
137
- Akero::replate(@cert.to_s, Akero::PLATE_CERT)
142
+ Akero.replate(@cert.to_s, Akero::PLATE_CERT)
138
143
  end
139
144
 
140
145
  # Private key (do not share this with anyone!)
141
- #
146
+ #
142
147
  # @example Save and load an Akero identity
143
148
  # alice = Akero.new
144
149
  # # Save
145
150
  # File.open('/tmp/alice.akr', 'w') { |f| f.write(alice.private_key) }
146
151
  # # Load
147
152
  # new_alice = Akero.load(File.read('/tmp/alice.akr'))
148
- #
153
+ #
149
154
  # @return [String] Private key (ascii armored)
150
155
  # @see Akero#load
151
156
  def private_key
@@ -156,7 +161,7 @@ class Akero
156
161
  out << cert_der
157
162
  out << @key.to_der
158
163
  out.insert(0, OpenSSL::Digest::SHA512.new(out).digest)
159
- PKEY_HEADER+Base64.encode64(out)+PKEY_FOOTER
164
+ PKEY_HEADER + Base64.encode64(out) + PKEY_FOOTER
160
165
  end
161
166
 
162
167
  # Sign a message.
@@ -164,7 +169,7 @@ class Akero
164
169
  # @param [String] plaintext The message to sign (binary safe)
165
170
  # @param [Boolean] ascii_armor Convert the output in base64?
166
171
  # @return [String] Akero signed message
167
- def sign(plaintext, ascii_armor=true)
172
+ def sign(plaintext, ascii_armor = true)
168
173
  out = _sign(plaintext)
169
174
  ascii_armor ? Akero.replate(out.to_s, Akero::PLATE_SIGNED) : out.to_der
170
175
  end
@@ -189,20 +194,20 @@ class Akero
189
194
  # @param [String] plaintext The message to encrypt (binary safe)
190
195
  # @param [Boolean] ascii_armor Convert the output to base64?
191
196
  # @return [String] Akero secret message
192
- def encrypt(to, plaintext, ascii_armor=true)
197
+ def encrypt(to, plaintext, ascii_armor = true)
193
198
  to = [to] unless to.is_a? Array
194
- to = to.map { |e|
199
+ to = to.map do |e|
195
200
  case e
196
- when String
197
- begin
198
- OpenSSL::X509::Certificate.new(Akero.replate(e, Akero::PLATE_CERT, true))
199
- rescue OpenSSL::X509::CertificateError
200
- raise RuntimeError, ERR_INVALID_RECIPIENT_CERT
201
- end
202
- else
203
- raise RuntimeError, ERR_INVALID_RECIPIENT
201
+ when String
202
+ begin
203
+ OpenSSL::X509::Certificate.new(Akero.replate(e, Akero::PLATE_CERT, true))
204
+ rescue OpenSSL::X509::CertificateError
205
+ raise ERR_INVALID_RECIPIENT_CERT
206
+ end
207
+ else
208
+ raise ERR_INVALID_RECIPIENT
204
209
  end
205
- }
210
+ end
206
211
  out = _sign(_encrypt(to, _sign(plaintext, false)))
207
212
  ascii_armor ? Akero.replate(out.to_s, PLATE_CRYPTED) : out.to_der
208
213
  end
@@ -218,21 +223,21 @@ class Akero
218
223
  begin
219
224
  body, signer_cert, body_type = verify(ciphertext, nil)
220
225
  rescue ArgumentError
221
- raise RuntimeError, ERR_MSG_MALFORMED_ENV
226
+ raise ERR_MSG_MALFORMED_ENV
222
227
  end
223
228
 
224
229
  case body_type.ord
225
- when 0x00
226
- # public message (signed)
227
- return Message.new(body, signer_cert, :signed)
228
- when 0x01
229
- # private message (signed, crypted, signed)
230
- signed_plaintext = _decrypt(body)
231
- plaintext, verified_cert, body_type = verify(signed_plaintext, signer_cert)
232
- msg = Message.new(plaintext, signer_cert, :encrypted)
233
- return msg
230
+ when 0x00
231
+ # public message (signed)
232
+ return Message.new(body, signer_cert, :signed)
233
+ when 0x01
234
+ # private message (signed, crypted, signed)
235
+ signed_plaintext = _decrypt(body)
236
+ plaintext, _verified_cert, _body_type = verify(signed_plaintext, signer_cert)
237
+ msg = Message.new(plaintext, signer_cert, :encrypted)
238
+ return msg
234
239
  end
235
- raise RuntimeError, ERR_MSG_MALFORMED_BODY
240
+ raise ERR_MSG_MALFORMED_BODY
236
241
  end
237
242
 
238
243
  # @private
@@ -244,9 +249,9 @@ class Akero
244
249
  def to_s
245
250
  inspect
246
251
  end
247
-
252
+
248
253
  #---------------------------------------------------------------------------
249
- protected
254
+ class << self; protected; end
250
255
 
251
256
  # Swap the "license plates" on an ascii-armored message.
252
257
  # This is done for user-friendliness, so stored Akero
@@ -256,9 +261,9 @@ class Akero
256
261
  # @param [Array] plates Array of the two plates to swap
257
262
  # @param [Boolean] reverse Reverse the swap?
258
263
  # @return [String] The replated message
259
- def self.replate(msg, plates, reverse=false)
260
- a,b = reverse ? [1,0] : [0,1]
261
- "-----BEGIN #{plates[b]}-----#{msg.strip[plates[a].length+16..-(plates[a].length+15)]}-----END #{plates[b]}-----\n"
264
+ def self.replate(msg, plates, reverse = false)
265
+ a, b = reverse ? [1, 0] : [0, 1]
266
+ "-----BEGIN #{plates[b]}-----#{msg.strip[plates[a].length + 16..-(plates[a].length + 15)]}-----END #{plates[b]}-----\n"
262
267
  end
263
268
 
264
269
  # Extract fingerprint from an Akero public key.
@@ -268,37 +273,35 @@ class Akero
268
273
  cert.extensions.map.each do |e|
269
274
  return "AK:#{e.value}" if e.oid == 'subjectKeyIdentifier'
270
275
  end
271
- raise RuntimeError, ERR_CERT_CORRUPT
276
+ raise ERR_CERT_CORRUPT
272
277
  end
273
-
278
+
274
279
  #---------------------------------------------------------------------------
275
- private
280
+ private
276
281
 
277
282
  def _decrypt(crypted_msg)
278
- begin
279
- OpenSSL::PKCS7.new(crypted_msg).decrypt(@key, @cert)
280
- rescue OpenSSL::PKCS7::PKCS7Error, "decrypt error"
281
- raise RuntimeError, ERR_DECRYPT
282
- end
283
+ OpenSSL::PKCS7.new(crypted_msg).decrypt(@key, @cert)
284
+ rescue OpenSSL::PKCS7::PKCS7Error, 'decrypt error'
285
+ raise ERR_DECRYPT
283
286
  end
284
287
 
285
- def _encrypt(to, msg, cipher=nil)
286
- cipher ||= OpenSSL::Cipher::new("AES-256-CFB")
287
- OpenSSL::PKCS7::encrypt(to, msg.to_der, cipher, OpenSSL::PKCS7::BINARY)
288
+ def _encrypt(to, msg, cipher = nil)
289
+ cipher ||= OpenSSL::Cipher.new('AES-256-CFB')
290
+ OpenSSL::PKCS7.encrypt(to, msg.to_der, cipher, OpenSSL::PKCS7::BINARY)
288
291
  end
289
292
 
290
- def _sign(message, embed_cert=true)
293
+ def _sign(message, embed_cert = true)
291
294
  flags = embed_cert ? OpenSSL::PKCS7::BINARY : (OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::NOCERTS)
292
295
  case message
293
- when String
294
- type = 0x00
295
- when OpenSSL::PKCS7
296
- type = 0x01
297
- else
298
- raise RuntimeError, ERR_MSG_NOT_STRING_NOR_PKCS7
296
+ when String
297
+ type = 0x00
298
+ when OpenSSL::PKCS7
299
+ type = 0x01
300
+ else
301
+ raise ERR_MSG_NOT_STRING_NOR_PKCS7
299
302
  end
300
303
  message = message.to_der if message.is_a? OpenSSL::PKCS7
301
- OpenSSL::PKCS7::sign(@cert, @key, type.chr + message, [], flags)
304
+ OpenSSL::PKCS7.sign(@cert, @key, type.chr + message, [], flags)
302
305
  end
303
306
 
304
307
  def verify(signed_msg, cert)
@@ -306,15 +309,15 @@ class Akero
306
309
  store = OpenSSL::X509::Store.new
307
310
 
308
311
  if cert.nil?
309
- if signed_msg.certificates.nil? or signed_msg.certificates.length != 1
310
- raise RuntimeError, ERR_MSG_TOO_MANY_SIGNERS
312
+ if signed_msg.certificates.nil? || signed_msg.certificates.length != 1
313
+ raise ERR_MSG_TOO_MANY_SIGNERS
311
314
  end
312
315
 
313
316
  cert = signed_msg.certificates[0]
314
317
  end
315
318
 
316
319
  unless signed_msg.verify([cert], store, nil, OpenSSL::PKCS7::NOINTERN | OpenSSL::PKCS7::NOVERIFY)
317
- raise RuntimeError, ERR_MSG_CORRUPT_CERT
320
+ raise ERR_MSG_CORRUPT_CERT
318
321
  end
319
322
 
320
323
  [signed_msg.data[1..-1], cert, signed_msg.data[0]]
@@ -325,7 +328,7 @@ class Akero
325
328
  # @param [Integer] rsa_bits RSA key length
326
329
  # @param [OpenSSL::Digest] digest Signature digest
327
330
  # @return [Array] rsa_keypair, certificate
328
- def generate_keypair(rsa_bits=DEFAULT_RSA_BITS, digest=DEFAULT_DIGEST)
331
+ def generate_keypair(rsa_bits = DEFAULT_RSA_BITS, digest = DEFAULT_DIGEST)
329
332
  cn = "Akero #{Akero::VERSION}"
330
333
  rsa = OpenSSL::PKey::RSA.new(rsa_bits)
331
334
 
@@ -337,20 +340,19 @@ class Akero
337
340
  cert.issuer = name
338
341
  cert.not_before = Time.now
339
342
  # valid until 2038-01-19 04:14:06 +0100
340
- cert.not_after = Time.at(2147483646)
343
+ cert.not_after = Time.at(2_147_483_646)
341
344
  cert.public_key = rsa.public_key
342
-
345
+
343
346
  ef = OpenSSL::X509::ExtensionFactory.new(nil, cert)
344
347
  ef.issuer_certificate = cert
345
348
  cert.extensions = [
346
- ef.create_extension("basicConstraints","CA:FALSE"),
347
- ef.create_extension("subjectKeyIdentifier", "hash"),
349
+ ef.create_extension('basicConstraints', 'CA:FALSE'),
350
+ ef.create_extension('subjectKeyIdentifier', 'hash')
348
351
  ]
349
- aki = ef.create_extension("authorityKeyIdentifier",
350
- "keyid:always,issuer:always")
352
+ aki = ef.create_extension('authorityKeyIdentifier',
353
+ 'keyid:always,issuer:always')
351
354
  cert.add_extension(aki)
352
355
  cert.sign(rsa, digest.new)
353
356
  [rsa, cert]
354
357
  end
355
358
  end
356
-
data/spec/akero_spec.rb CHANGED
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
  require 'openssl'
3
4
 
4
5
  describe Akero do
5
6
  subject { Akero.new(1024) }
6
7
  describe '#new' do
7
- it "returns instance with unique fingerprint" do
8
+ it 'returns instance with unique fingerprint' do
8
9
  memo = {}
9
10
  10.times do
10
11
  id = Akero.new.id
@@ -15,7 +16,7 @@ describe Akero do
15
16
  end
16
17
 
17
18
  describe '#id' do
18
- it "returns a String that looks like an Akero fingerprint" do
19
+ it 'returns a String that looks like an Akero fingerprint' do
19
20
  subject.id.should be_a String
20
21
  subject.id.should match /^AK(:([a-fA-Z0-9]){2}){20}$/
21
22
  end
@@ -23,13 +24,13 @@ describe Akero do
23
24
 
24
25
  describe '#private_key' do
25
26
  describe 'return value' do
26
- it "is a String that looks like an Akero private key" do
27
+ it 'is a String that looks like an Akero private key' do
27
28
  subject.private_key.should be_a String
28
29
  subject.private_key.should match /^#{Akero::PKEY_HEADER}/
29
30
  subject.private_key.should match /\n#{Akero::PKEY_FOOTER}$/
30
31
  end
31
32
 
32
- it "can be loaded by Akero" do
33
+ it 'can be loaded by Akero' do
33
34
  bob = Akero.load(subject.private_key)
34
35
  bob.id.should == subject.id
35
36
  bob.public_key.should == subject.public_key
@@ -39,29 +40,29 @@ describe Akero do
39
40
 
40
41
  describe '#public_key' do
41
42
  describe 'return value' do
42
- it "is a String that looks like an Akero public key" do
43
+ it 'is a String that looks like an Akero public key' do
43
44
  subject.public_key.should be_a String
44
45
  subject.public_key.should match /^-----BEGIN #{Akero::PLATE_CERT[1]}-----\n/
45
46
  subject.public_key.should match /\n-----END #{Akero::PLATE_CERT[1]}-----\n$/
46
47
  end
47
48
 
48
- it "raises RuntimeError when trying to load as private key" do
49
- lambda {
49
+ it 'raises RuntimeError when trying to load as private key' do
50
+ lambda do
50
51
  bob = Akero.load(subject.public_key)
51
52
  bob.id.should == subject.id
52
53
  bob.public_key.should == subject.public_key
53
- }.should raise_error RuntimeError, Akero::ERR_PKEY_CORRUPT
54
+ end.should raise_error RuntimeError, Akero::ERR_PKEY_CORRUPT
54
55
  end
55
56
  end
56
57
  end
57
58
 
58
59
  describe '#sign' do
59
- ([true, false]).each do |ascii_armor|
60
+ [true, false].each do |ascii_armor|
60
61
  describe "ascii_armor=#{ascii_armor}" do
61
62
  describe 'return value' do
62
63
  if ascii_armor
63
- it "is a String that looks like an Akero signed message" do
64
- plaintext = "Hello world!"
64
+ it 'is a String that looks like an Akero signed message' do
65
+ plaintext = 'Hello world!'
65
66
  signed_msg = subject.sign(plaintext, ascii_armor)
66
67
  signed_msg.should be_a String
67
68
  signed_msg.should match /^-----BEGIN #{Akero::PLATE_SIGNED[1]}-----\n/
@@ -69,8 +70,8 @@ describe Akero do
69
70
  end
70
71
  end
71
72
 
72
- it "contains valid signature" do
73
- plaintext = "Hello world!"
73
+ it 'contains valid signature' do
74
+ plaintext = 'Hello world!'
74
75
  signed_msg = subject.sign(plaintext, ascii_armor)
75
76
  bob = Akero.new
76
77
  msg = bob.receive(signed_msg)
@@ -85,12 +86,12 @@ describe Akero do
85
86
  end
86
87
 
87
88
  describe '#encrypt' do
88
- ([true, false]).each do |ascii_armor|
89
+ [true, false].each do |ascii_armor|
89
90
  describe "ascii_armor=#{ascii_armor}" do
90
91
  describe 'return value' do
91
92
  if ascii_armor
92
- it "is a String that looks like an Akero secret message" do
93
- plaintext = "Hello world!"
93
+ it 'is a String that looks like an Akero secret message' do
94
+ plaintext = 'Hello world!'
94
95
  ciphertext = subject.encrypt(subject.public_key, plaintext, ascii_armor)
95
96
  ciphertext.should be_a String
96
97
  ciphertext.should match /^-----BEGIN #{Akero::PLATE_CRYPTED[1]}-----\n/
@@ -98,25 +99,25 @@ describe Akero do
98
99
  end
99
100
  end
100
101
 
101
- it "raises RuntimeError on invalid recipient (invalid public key)" do
102
- lambda {
103
- msg = "Hello world!"
102
+ it 'raises RuntimeError on invalid recipient (invalid public key)' do
103
+ lambda do
104
+ msg = 'Hello world!'
104
105
  ciphertext = subject.encrypt([subject.public_key, 'foo'], msg)
105
- }.should raise_error RuntimeError, Akero::ERR_INVALID_RECIPIENT_CERT
106
+ end.should raise_error RuntimeError, Akero::ERR_INVALID_RECIPIENT_CERT
106
107
  end
107
108
 
108
- it "raises RuntimeError on invalid recipient (wrong type)" do
109
- lambda {
110
- msg = "Hello world!"
109
+ it 'raises RuntimeError on invalid recipient (wrong type)' do
110
+ lambda do
111
+ msg = 'Hello world!'
111
112
  ciphertext = subject.encrypt([subject.public_key, 42], msg)
112
- }.should raise_error RuntimeError, Akero::ERR_INVALID_RECIPIENT
113
+ end.should raise_error RuntimeError, Akero::ERR_INVALID_RECIPIENT
113
114
  end
114
115
 
115
- it "raises RuntimeError when message is not String" do
116
- lambda {
117
- msg = "Hello world!"
116
+ it 'raises RuntimeError when message is not String' do
117
+ lambda do
118
+ msg = 'Hello world!'
118
119
  ciphertext = subject.encrypt(subject.public_key, 42)
119
- }.should raise_error RuntimeError, Akero::ERR_MSG_NOT_STRING_NOR_PKCS7
120
+ end.should raise_error RuntimeError, Akero::ERR_MSG_NOT_STRING_NOR_PKCS7
120
121
  end
121
122
  end
122
123
  end
@@ -124,18 +125,18 @@ describe Akero do
124
125
  end
125
126
 
126
127
  describe '#receive' do
127
- ([true, false]).each do |ascii_armor|
128
+ [true, false].each do |ascii_armor|
128
129
  describe "ascii_armor=#{ascii_armor}" do
129
- it "decrypts message that was encrypted for self" do
130
- plaintext = "Hello world!"
130
+ it 'decrypts message that was encrypted for self' do
131
+ plaintext = 'Hello world!'
131
132
  ciphertext = subject.encrypt(subject.public_key, plaintext, ascii_armor)
132
133
  msg = subject.receive(ciphertext)
133
134
  msg.body.should == plaintext
134
135
  msg.type.should == :encrypted
135
136
  end
136
137
 
137
- it "decrypts message that was encrypted for self and other recipients" do
138
- plaintext = "Hello world!"
138
+ it 'decrypts message that was encrypted for self and other recipients' do
139
+ plaintext = 'Hello world!'
139
140
  alice = Akero.new
140
141
  bob = Akero.new
141
142
  ciphertext = subject.encrypt([alice.public_key, subject.public_key, bob.public_key], plaintext, ascii_armor)
@@ -144,20 +145,20 @@ describe Akero do
144
145
  msg.type.should == :encrypted
145
146
  end
146
147
 
147
- it "fails to decrypt message that was encrypted only for other recipients" do
148
- lambda {
149
- plaintext = "Hello world!"
148
+ it 'fails to decrypt message that was encrypted only for other recipients' do
149
+ lambda do
150
+ plaintext = 'Hello world!'
150
151
  alice = Akero.new
151
152
  bob = Akero.new
152
153
  ciphertext = subject.encrypt([alice.public_key, bob.public_key], plaintext, ascii_armor)
153
154
  msg = subject.receive(ciphertext)
154
155
  msg.body.should == plaintext
155
156
  msg.type.should == :encrypted
156
- }.should raise_error RuntimeError, Akero::ERR_DECRYPT
157
+ end.should raise_error RuntimeError, Akero::ERR_DECRYPT
157
158
  end
158
159
 
159
- it "extracts signature from signed message" do
160
- plaintext = "Hello world!"
160
+ it 'extracts signature from signed message' do
161
+ plaintext = 'Hello world!'
161
162
  alice = Akero.new
162
163
  signed_msg = subject.sign(plaintext, ascii_armor)
163
164
  msg = alice.receive(signed_msg)
@@ -165,82 +166,82 @@ describe Akero do
165
166
  msg.type.should == :signed
166
167
  end
167
168
 
168
- it "raises RuntimeError on invalid message" do
169
- lambda {
170
- subject.receive("foobar")
171
- }.should raise_error RuntimeError #, Akero::ERR_MSG_MALFORMED_ENV
169
+ it 'raises RuntimeError on invalid message' do
170
+ lambda do
171
+ subject.receive('foobar')
172
+ end.should raise_error RuntimeError # , Akero::ERR_MSG_MALFORMED_ENV
172
173
  end
173
174
 
174
- it "raises RuntimeError when payload does not match envelope signature" do
175
- lambda {
175
+ it 'raises RuntimeError when payload does not match envelope signature' do
176
+ lambda do
176
177
  oscar = Akero.new
177
178
  raw_key = subject.send(:instance_variable_get, '@cert')
178
179
  a = subject.send(:_encrypt, [raw_key], subject.send(:_sign, 'foobar'))
179
180
  b = oscar.send(:_sign, a)
180
181
  c = ascii_armor ? Akero.replate(b.to_s, Akero::PLATE_CRYPTED) : b.to_der
181
182
  subject.receive(c)
182
- }.should raise_error RuntimeError, Akero::ERR_MSG_CORRUPT_CERT
183
+ end.should raise_error RuntimeError, Akero::ERR_MSG_CORRUPT_CERT
183
184
  end
184
185
 
185
- it "raises RuntimeError on malformed inner message" do
186
- lambda {
186
+ it 'raises RuntimeError on malformed inner message' do
187
+ lambda do
187
188
  key, cert = subject.send(:generate_keypair, 1024)
188
- env = OpenSSL::PKCS7::sign(cert, key, 0xff.chr, [], OpenSSL::PKCS7::BINARY)
189
+ env = OpenSSL::PKCS7.sign(cert, key, 0xff.chr, [], OpenSSL::PKCS7::BINARY)
189
190
  broken_msg = Akero.replate(env.to_s, Akero::PLATE_CRYPTED)
190
191
  subject.receive(broken_msg)
191
- }.should raise_error RuntimeError, Akero::ERR_MSG_MALFORMED_BODY
192
+ end.should raise_error RuntimeError, Akero::ERR_MSG_MALFORMED_BODY
192
193
  end
193
194
 
194
- it "raises RuntimeError on unsigned message" do
195
- lambda {
195
+ it 'raises RuntimeError on unsigned message' do
196
+ lambda do
196
197
  raw_key = subject.send(:instance_variable_get, '@cert')
197
- env = OpenSSL::PKCS7::encrypt([raw_key], 'foobar', OpenSSL::Cipher::new("AES-256-CFB"), OpenSSL::PKCS7::BINARY)
198
+ env = OpenSSL::PKCS7.encrypt([raw_key], 'foobar', OpenSSL::Cipher.new('AES-256-CFB'), OpenSSL::PKCS7::BINARY)
198
199
  broken_msg = Akero.replate(env.to_s, Akero::PLATE_CRYPTED)
199
200
  subject.receive(broken_msg)
200
- }.should raise_error RuntimeError, Akero::ERR_MSG_TOO_MANY_SIGNERS
201
+ end.should raise_error RuntimeError, Akero::ERR_MSG_TOO_MANY_SIGNERS
201
202
  end
202
203
  end
203
204
  end
204
205
  end
205
-
206
+
206
207
  describe '#verify' do
207
- it "raises RuntimeError when embedded certificate can not be verified" do
208
- lambda {
208
+ it 'raises RuntimeError when embedded certificate can not be verified' do
209
+ lambda do
209
210
  fake_msg = mock('fake_msg')
210
211
  fake_msg.stub(:verify).and_return(false)
211
212
  fake_msg.stub_chain(:certificates, :length).and_return(1)
212
213
  fake_msg.stub_chain(:certificates, :[]).and_return(nil)
213
214
  subject.send(:verify, fake_msg, nil)
214
- }.should raise_error RuntimeError, Akero::ERR_MSG_CORRUPT_CERT
215
+ end.should raise_error RuntimeError, Akero::ERR_MSG_CORRUPT_CERT
215
216
  end
216
217
  end
217
218
 
218
219
  describe '#inspect' do
219
- it "returns a summary String" do
220
+ it 'returns a summary String' do
220
221
  s = subject.inspect
221
222
  s.should match /id=AK:/
222
223
  end
223
224
  end
224
225
 
225
226
  describe '#to_s' do
226
- it "returns the same value as #inspect" do
227
+ it 'returns the same value as #inspect' do
227
228
  subject.to_s.should == subject.inspect
228
229
  end
229
230
  end
230
-
231
+
231
232
  describe '.fingerprint_from_cert' do
232
- it "raises RuntimeError on invalid cert" do
233
+ it 'raises RuntimeError on invalid cert' do
233
234
  mock_cert = mock('mock_cert')
234
235
  mock_cert.stub_chain(:extensions, :map, :each).and_return(nil)
235
- lambda {
236
+ lambda do
236
237
  Akero.fingerprint_from_cert(mock_cert)
237
- }.should raise_error RuntimeError, Akero::ERR_CERT_CORRUPT
238
+ end.should raise_error RuntimeError, Akero::ERR_CERT_CORRUPT
238
239
  end
239
240
  end
240
241
 
241
242
  describe Akero::Message do
242
243
  describe '#inspect' do
243
- it "returns a summary String" do
244
+ it 'returns a summary String' do
244
245
  signed_msg = subject.sign('')
245
246
  msg = subject.receive(signed_msg)
246
247
  s = msg.inspect
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'simplecov'
2
3
  SimpleCov.start
3
4