jose 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.gitignore +9 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/CODE_OF_CONDUCT.md +13 -0
  8. data/Gemfile +20 -0
  9. data/LICENSE.txt +373 -0
  10. data/README.md +41 -0
  11. data/Rakefile +10 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +7 -0
  14. data/jose.gemspec +36 -0
  15. data/lib/jose.rb +61 -0
  16. data/lib/jose/jwa.rb +21 -0
  17. data/lib/jose/jwa/aes_kw.rb +105 -0
  18. data/lib/jose/jwa/concat_kdf.rb +50 -0
  19. data/lib/jose/jwa/pkcs1.rb +269 -0
  20. data/lib/jose/jwa/pkcs7.rb +23 -0
  21. data/lib/jose/jwe.rb +290 -0
  22. data/lib/jose/jwe/alg.rb +12 -0
  23. data/lib/jose/jwe/alg_aes_gcm_kw.rb +98 -0
  24. data/lib/jose/jwe/alg_aes_kw.rb +57 -0
  25. data/lib/jose/jwe/alg_dir.rb +40 -0
  26. data/lib/jose/jwe/alg_ecdh_es.rb +123 -0
  27. data/lib/jose/jwe/alg_pbes2.rb +90 -0
  28. data/lib/jose/jwe/alg_rsa.rb +63 -0
  29. data/lib/jose/jwe/enc.rb +8 -0
  30. data/lib/jose/jwe/enc_aes_cbc_hmac.rb +80 -0
  31. data/lib/jose/jwe/enc_aes_gcm.rb +68 -0
  32. data/lib/jose/jwe/zip.rb +7 -0
  33. data/lib/jose/jwe/zip_def.rb +28 -0
  34. data/lib/jose/jwk.rb +347 -0
  35. data/lib/jose/jwk/kty.rb +34 -0
  36. data/lib/jose/jwk/kty_ec.rb +179 -0
  37. data/lib/jose/jwk/kty_oct.rb +104 -0
  38. data/lib/jose/jwk/kty_rsa.rb +185 -0
  39. data/lib/jose/jwk/pem.rb +19 -0
  40. data/lib/jose/jwk/set.rb +2 -0
  41. data/lib/jose/jws.rb +242 -0
  42. data/lib/jose/jws/alg.rb +10 -0
  43. data/lib/jose/jws/alg_ecdsa.rb +41 -0
  44. data/lib/jose/jws/alg_hmac.rb +41 -0
  45. data/lib/jose/jws/alg_rsa_pkcs1_v1_5.rb +41 -0
  46. data/lib/jose/jws/alg_rsa_pss.rb +41 -0
  47. data/lib/jose/jwt.rb +145 -0
  48. data/lib/jose/version.rb +3 -0
  49. metadata +162 -0
@@ -0,0 +1,7 @@
1
+ module JOSE::JWE::ZIP
2
+
3
+ extend self
4
+
5
+ end
6
+
7
+ require 'jose/jwe/zip_def'
@@ -0,0 +1,28 @@
1
+ class JOSE::JWE::ZIP_DEF
2
+
3
+ # JOSE::JWE callbacks
4
+
5
+ def self.from_map(fields)
6
+ case fields['zip']
7
+ when 'DEF'
8
+ return new(), fields.except('zip')
9
+ else
10
+ raise ArgumentError, "invalid 'zip' for JWE: #{fields['zip'].inspect}"
11
+ end
12
+ end
13
+
14
+ def to_map(fields)
15
+ return fields.put('zip', 'DEF')
16
+ end
17
+
18
+ # JOSE::JWE::ZIP callbacks
19
+
20
+ def compress(plain_text)
21
+ return Zlib.deflate(plain_text)
22
+ end
23
+
24
+ def uncompress(cipher_text)
25
+ return Zlib.inflate(cipher_text)
26
+ end
27
+
28
+ end
data/lib/jose/jwk.rb ADDED
@@ -0,0 +1,347 @@
1
+ module JOSE
2
+ class JWK < Struct.new(:keys, :kty, :fields)
3
+
4
+ # Decode API
5
+
6
+ def self.from(object, modules = nil, key = nil)
7
+ case object
8
+ when JOSE::Map, Hash
9
+ return from_map(object, modules, key)
10
+ when String
11
+ return from_binary(object, modules, key)
12
+ when JOSE::JWK
13
+ return object
14
+ else
15
+ raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWK"
16
+ end
17
+ end
18
+
19
+ def self.from_binary(object, modules = nil, key = nil)
20
+ if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
21
+ key = modules
22
+ modules = {}
23
+ end
24
+ modules ||= {}
25
+ case object
26
+ when String
27
+ if key
28
+ plain_text, jwe = JOSE::JWE.block_decrypt(key, object)
29
+ return from_binary(plain_text, modules), jwe
30
+ else
31
+ return from_map(JOSE.decode(object), modules)
32
+ end
33
+ else
34
+ raise ArgumentError, "'object' must be a String"
35
+ end
36
+ end
37
+
38
+ def self.from_file(file, modules = nil, key = nil)
39
+ return from_binary(File.binread(file), modules, key)
40
+ end
41
+
42
+ def self.from_key(object, modules = {})
43
+ kty = modules[:kty] || JOSE::JWK::KTY
44
+ return JOSE::JWK.new(nil, *kty.from_key(object))
45
+ end
46
+
47
+ def self.from_map(object, modules = nil, key = nil)
48
+ if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
49
+ key = modules
50
+ modules = {}
51
+ end
52
+ modules ||= {}
53
+ case object
54
+ when JOSE::Map, Hash
55
+ if key
56
+ plain_text, jwe = JOSE::JWE.block_decrypt(key, object)
57
+ return from_binary(plain_text, modules), jwe
58
+ else
59
+ return from_fields(JOSE::JWK.new(nil, nil, JOSE::Map.new(object)), modules)
60
+ end
61
+ else
62
+ raise ArgumentError, "'object' must be a String"
63
+ end
64
+ end
65
+
66
+ def self.from_pem(object, modules = nil, password = nil)
67
+ if modules.is_a?(String) and password.nil?
68
+ password = modules
69
+ modules = {}
70
+ end
71
+ modules ||= {}
72
+ kty = modules[:kty] || JOSE::JWK::PEM
73
+ return JOSE::JWK.new(nil, *kty.from_binary(object, password))
74
+ end
75
+
76
+ def self.from_pem_file(file, modules = nil, password = nil)
77
+ return from_pem(File.binread(file), modules, password)
78
+ end
79
+
80
+ def self.from_oct(object, modules = {})
81
+ kty = modules[:kty] || JOSE::JWK::KTY_oct
82
+ return JOSE::JWK.new(nil, *kty.from_oct(object))
83
+ end
84
+
85
+ def self.from_oct_file(file, modules = {})
86
+ return from_oct(File.binread(file), modules)
87
+ end
88
+
89
+ # Encode API
90
+
91
+ def self.to_binary(jwk, key = nil, jwe = nil)
92
+ return from(jwk).to_binary(key, jwe)
93
+ end
94
+
95
+ def to_binary(key = nil, jwe = nil)
96
+ if not key.nil?
97
+ jwe ||= kty.key_encryptor(fields, key)
98
+ end
99
+ if key and jwe
100
+ return to_map(key, jwe).compact
101
+ else
102
+ return JOSE.encode(to_map)
103
+ end
104
+ end
105
+
106
+ def self.to_file(jwk, file, key = nil, jwe = nil)
107
+ return from(jwk).to_file(file, key, jwe)
108
+ end
109
+
110
+ def to_file(file, key = nil, jwe = nil)
111
+ return File.binwrite(file, to_binary(key, jwe))
112
+ end
113
+
114
+ def self.to_key(jwk)
115
+ return from(jwk).to_key
116
+ end
117
+
118
+ def to_key
119
+ return kty.to_key
120
+ end
121
+
122
+ def self.to_map(jwk, key = nil, jwe = nil)
123
+ return from(jwk).to_map(key, jwe)
124
+ end
125
+
126
+ def to_map(key = nil, jwe = nil)
127
+ if not key.nil?
128
+ jwe ||= kty.key_encryptor(fields, key)
129
+ end
130
+ if key and jwe
131
+ return JOSE::JWE.block_encrypt(key, to_binary, jwe)
132
+ else
133
+ return kty.to_map(fields)
134
+ end
135
+ end
136
+
137
+ def self.to_oct(jwk)
138
+ return from(jwk).to_oct
139
+ end
140
+
141
+ def to_oct
142
+ return kty.to_oct
143
+ end
144
+
145
+ def self.to_pem(jwk, password = nil)
146
+ return from(jwk).to_pem(password)
147
+ end
148
+
149
+ def to_pem(password = nil)
150
+ return kty.to_pem(password)
151
+ end
152
+
153
+ def self.to_public(jwk)
154
+ return from(jwk).to_public
155
+ end
156
+
157
+ def to_public
158
+ return JOSE::JWK.from_map(to_public_map)
159
+ end
160
+
161
+ def self.to_public_key(jwk)
162
+ return from(jwk).to_public_key
163
+ end
164
+
165
+ def to_public_key
166
+ return to_public.to_key
167
+ end
168
+
169
+ def self.to_public_map(jwk)
170
+ return from(jwk).to_public_map
171
+ end
172
+
173
+ def to_public_map
174
+ return kty.to_public_map(fields)
175
+ end
176
+
177
+ def self.to_thumbprint_map(jwk)
178
+ return from(jwk).to_thumbprint_map
179
+ end
180
+
181
+ def to_thumbprint_map
182
+ return kty.to_thumbprint_map(fields)
183
+ end
184
+
185
+ # API
186
+
187
+ def self.block_decrypt(jwk, encrypted)
188
+ return from(jwk).block_decrypt(encrypted)
189
+ end
190
+
191
+ def block_decrypt(encrypted)
192
+ return JOSE::JWE.block_decrypt(self, encrypted)
193
+ end
194
+
195
+ def self.block_encrypt(jwk, plain_text, jwe = nil)
196
+ return from(jwk).block_encrypt(plain_text, jwe)
197
+ end
198
+
199
+ def block_encrypt(plain_text, jwe = nil)
200
+ jwe ||= kty.block_encryptor(fields, plain_text)
201
+ return JOSE::JWE.block_encrypt(self, plain_text, jwe)
202
+ end
203
+
204
+ def self.box_decrypt(jwk, encrypted)
205
+ return from(jwk).box_decrypt(encrypted)
206
+ end
207
+
208
+ def box_decrypt(encrypted)
209
+ return JOSE::JWE.block_decrypt(self, encrypted)
210
+ end
211
+
212
+ # Generates an ephemeral private key based on other public key curve.
213
+ def box_encrypt(plain_text, my_private_jwk = nil, jwe = nil)
214
+ generated_jwk = nil
215
+ other_public_jwk = self
216
+ if my_private_jwk.nil?
217
+ generated_jwk = my_private_jwk = other_public_jwk.generate_key
218
+ end
219
+ if not my_private_jwk.is_a?(JOSE::JWK)
220
+ my_private_jwk = JOSE::JWK.from(my_private_jwk)
221
+ end
222
+ if jwe.nil?
223
+ jwe = other_public_jwk.kty.block_encryptor(fields, plain_text)
224
+ end
225
+ if jwe.is_a?(Hash)
226
+ jwe = JOSE::Map.new(jwe)
227
+ end
228
+ if jwe.is_a?(JOSE::Map)
229
+ if jwe['apu'].nil?
230
+ jwe = jwe.put('apu', my_private_jwk.fields['kid'] || my_private_jwk.thumbprint)
231
+ end
232
+ if jwe['apv'].nil?
233
+ jwe = jwe.put('apv', other_public_jwk.fields['kid'] || other_public_jwk.thumbprint)
234
+ end
235
+ if jwe['epk'].nil?
236
+ jwe = jwe.put('epk', my_private_jwk.to_public_map)
237
+ end
238
+ end
239
+ if generated_jwk
240
+ return JOSE::JWE.block_encrypt([other_public_jwk, my_private_jwk], plain_text, jwe), generated_jwk
241
+ else
242
+ return JOSE::JWE.block_encrypt([other_public_jwk, my_private_jwk], plain_text, jwe)
243
+ end
244
+ end
245
+
246
+ def derive_key(*args)
247
+ return kty.derive_key(*args)
248
+ end
249
+
250
+ def self.generate_key(params)
251
+ if params.is_a?(Array) and (params.length == 2 or params.length == 3)
252
+ case params[0]
253
+ when :ec
254
+ return JOSE::JWK.new(nil, *JOSE::JWK::KTY_EC.generate_key(params))
255
+ when :oct
256
+ return JOSE::JWK.new(nil, *JOSE::JWK::KTY_oct.generate_key(params))
257
+ when :rsa
258
+ return JOSE::JWK.new(nil, *JOSE::JWK::KTY_RSA.generate_key(params))
259
+ else
260
+ raise ArgumentError, "invalid key generation params"
261
+ end
262
+ elsif params.is_a?(JOSE::JWK)
263
+ return params.generate_key
264
+ elsif params.respond_to?(:generate_key)
265
+ return JOSE::JWK.new(nil, *params.generate_key(JOSE::Map[]))
266
+ else
267
+ raise ArgumentError, "invalid key generation params"
268
+ end
269
+ end
270
+
271
+ def generate_key
272
+ return JOSE::JWK.new(nil, *kty.generate_key(fields))
273
+ end
274
+
275
+ def self.sign(jwk, plain_text, jws = nil, header = nil)
276
+ return from(jwk).sign(plain_text, jws, header)
277
+ end
278
+
279
+ def sign(plain_text, jws = nil, header = nil)
280
+ jws ||= kty.signer(fields, plain_text)
281
+ return JOSE::JWS.sign(self, plain_text, jws, header)
282
+ end
283
+
284
+ def self.verify(signed, jwk)
285
+ return from(jwk).verify(signed)
286
+ end
287
+
288
+ def verify(signed)
289
+ return JOSE::JWS.verify(self, signed)
290
+ end
291
+
292
+ def self.verify_strict(signed, allow, jwk)
293
+ return from(jwk).verify_strict(signed, allow)
294
+ end
295
+
296
+ def verify_strict(signed, allow)
297
+ return JOSE::JWS.verify_strict(self, allow, signed)
298
+ end
299
+
300
+ # See https://tools.ietf.org/html/rfc7638
301
+ def self.thumbprint(digest_type, jwk = nil)
302
+ if jwk.nil?
303
+ jwk = digest_type
304
+ digest_type = nil
305
+ end
306
+ return from(jwk).thumbprint(digest_type)
307
+ end
308
+
309
+ def thumbprint(digest_type = nil)
310
+ digest_type ||= 'SHA256'
311
+ thumbprint_binary = JOSE.encode(to_thumbprint_map)
312
+ return JOSE.urlsafe_encode64(OpenSSL::Digest.new(digest_type).digest(thumbprint_binary))
313
+ end
314
+
315
+ private
316
+
317
+ def self.from_fields(jwk, modules)
318
+ if jwk.fields.has_key?('keys')
319
+ keys = modules[:keys] || JOSE::JWK::Set
320
+ jwk.keys, jwk.fields = keys.from_map(jwk.fields)
321
+ return from_fields(jwk, modules)
322
+ elsif jwk.fields.has_key?('kty')
323
+ kty = modules[:kty] || case jwk.fields['kty']
324
+ when 'EC'
325
+ JOSE::JWK::KTY_EC
326
+ when 'oct'
327
+ JOSE::JWK::KTY_oct
328
+ when 'RSA'
329
+ JOSE::JWK::KTY_RSA
330
+ else
331
+ raise ArgumentError, "unknown 'kty': #{jwk.fields['kty'].inspect}"
332
+ end
333
+ jwk.kty, jwk.fields = kty.from_map(jwk.fields)
334
+ return from_fields(jwk, modules)
335
+ elsif jwk.keys.nil? and jwk.kty.nil?
336
+ raise ArgumentError, "missing required keys: 'keys' or 'kty'"
337
+ else
338
+ return jwk
339
+ end
340
+ end
341
+
342
+ end
343
+ end
344
+
345
+ require 'jose/jwk/pem'
346
+ require 'jose/jwk/set'
347
+ require 'jose/jwk/kty'
@@ -0,0 +1,34 @@
1
+ module JOSE::JWK::KTY
2
+
3
+ extend self
4
+
5
+ def from_key(object)
6
+ case object
7
+ when OpenSSL::PKey::EC
8
+ return JOSE::JWK::KTY_EC.from_key(object)
9
+ when OpenSSL::PKey::RSA
10
+ return JOSE::JWK::KTY_RSA.from_key(object)
11
+ else
12
+ raise ArgumentError, "'object' is not a recognized key type"
13
+ end
14
+ end
15
+
16
+ def key_encryptor(kty, fields, key)
17
+ if key.is_a?(String)
18
+ return JOSE::Map[
19
+ 'alg' => 'PBES2-HS256+A128KW',
20
+ 'cty' => 'jwk+json',
21
+ 'enc' => 'A128GCM',
22
+ 'p2c' => 4096,
23
+ 'p2s' => JOSE.urlsafe_encode64(SecureRandom.random_bytes(16))
24
+ ]
25
+ else
26
+ raise ArgumentError, "unhandled key type for key_encryptor"
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ require 'jose/jwk/kty_ec'
33
+ require 'jose/jwk/kty_oct'
34
+ require 'jose/jwk/kty_rsa'
@@ -0,0 +1,179 @@
1
+ class JOSE::JWK::KTY_EC < Struct.new(:key)
2
+
3
+ # JOSE::JWK callbacks
4
+
5
+ def self.from_map(fields)
6
+ if fields['kty'] == 'EC' and fields['crv'].is_a?(String) and fields['x'].is_a?(String) and fields['y'].is_a?(String)
7
+ crv = case fields['crv']
8
+ when 'P-256'
9
+ 'prime256v1'
10
+ when 'P-384'
11
+ 'secp384r1'
12
+ when 'P-521'
13
+ 'secp521r1'
14
+ else
15
+ raise ArgumentError, "invalid 'EC' JWK"
16
+ end
17
+ ec = OpenSSL::PKey::EC.new(crv)
18
+ x = JOSE.urlsafe_decode64(fields['x'])
19
+ y = JOSE.urlsafe_decode64(fields['y'])
20
+ ec.public_key = OpenSSL::PKey::EC::Point.new(
21
+ OpenSSL::PKey::EC::Group.new(crv),
22
+ OpenSSL::BN.new([0x04, x, y].pack('CA*A*'), 2)
23
+ )
24
+ if fields['d'].is_a?(String)
25
+ ec.private_key = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
26
+ end
27
+ return JOSE::JWK::KTY_EC.new(ec), fields.except('kty', 'crv', 'd', 'x', 'y')
28
+ else
29
+ raise ArgumentError, "invalid 'EC' JWK"
30
+ end
31
+ end
32
+
33
+ def to_key
34
+ return key
35
+ end
36
+
37
+ def to_map(fields)
38
+ ec_point = key.public_key.to_bn.to_s(2)
39
+ ec_point_x, ec_point_y = case ec_point.bytesize
40
+ when 65
41
+ ec_point.unpack('xA32A32')
42
+ when 97
43
+ ec_point.unpack('xA48A48')
44
+ when 133
45
+ ec_point.unpack('xA66A66')
46
+ else
47
+ raise ArgumentError, "unhandled EC point size: #{ec_point.bytesize.inspect}"
48
+ end
49
+ crv = case key.group.curve_name
50
+ when 'prime256v1', 'secp256r1'
51
+ 'P-256'
52
+ when 'secp384r1'
53
+ 'P-384'
54
+ when 'secp521r1'
55
+ 'P-521'
56
+ else
57
+ raise ArgumentError, "unhandled EC curve name: #{key.group.curve_name.inspect}"
58
+ end
59
+ if key.private_key?
60
+ return fields.
61
+ put('crv', crv).
62
+ put('d', JOSE.urlsafe_encode64(key.private_key.to_s(2))).
63
+ put('kty', 'EC').
64
+ put('x', JOSE.urlsafe_encode64(ec_point_x)).
65
+ put('y', JOSE.urlsafe_encode64(ec_point_y))
66
+ else
67
+ return fields.
68
+ put('crv', crv).
69
+ put('kty', 'EC').
70
+ put('x', JOSE.urlsafe_encode64(ec_point_x)).
71
+ put('y', JOSE.urlsafe_encode64(ec_point_y))
72
+ end
73
+ end
74
+
75
+ def to_public_map(fields)
76
+ return to_map(fields).except('d')
77
+ end
78
+
79
+ def to_thumbprint_map(fields)
80
+ return to_public_map(fields).slice('crv', 'kty', 'x', 'y')
81
+ end
82
+
83
+ # JOSE::JWK::KTY callbacks
84
+
85
+ def block_encryptor(fields, plain_text)
86
+ return JOSE::Map[
87
+ 'alg' => 'ECDH-ES',
88
+ 'enc' => 'A128GCM'
89
+ ]
90
+ end
91
+
92
+ def derive_key(my_private_key)
93
+ if my_private_key.is_a?(JOSE::JWK)
94
+ my_private_key = my_private_key.to_key
95
+ end
96
+ if my_private_key.private_key?
97
+ return my_private_key.dh_compute_key(key.public_key)
98
+ else
99
+ raise ArgumentError, "derive_key requires a private key as an argument"
100
+ end
101
+ end
102
+
103
+ def self.generate_key(curve_name)
104
+ if curve_name.is_a?(Array) and curve_name.length == 2 and curve_name[0] == :ec
105
+ curve_name = curve_name[1]
106
+ end
107
+ if curve_name.is_a?(String)
108
+ return from_key(OpenSSL::PKey::EC.new(curve_name).generate_key)
109
+ else
110
+ raise ArgumentError, "'curve_name' must be a String"
111
+ end
112
+ end
113
+
114
+ def generate_key(fields)
115
+ kty, other_fields = JOSE::JWK::KTY_EC.generate_key([:ec, key.group.curve_name])
116
+ return kty, fields.delete('kid').merge(other_fields)
117
+ end
118
+
119
+ def key_encryptor(fields, key)
120
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
121
+ end
122
+
123
+ def sign(message, digest_type)
124
+ asn1_signature = key.dsa_sign_asn1(digest_type.digest(message))
125
+ asn1_sequence = OpenSSL::ASN1.decode(asn1_signature)
126
+ rbin = asn1_sequence.value[0].value.to_s(2)
127
+ sbin = asn1_sequence.value[1].value.to_s(2)
128
+ size = [rbin.bytesize, sbin.bytesize].max
129
+ rpad = pad(rbin, size)
130
+ spad = pad(sbin, size)
131
+ return rpad.concat(spad)
132
+ end
133
+
134
+ def signer(fields = nil, plain_text = nil)
135
+ if key.private_key?
136
+ return JOSE::Map['alg' => 'ES256']
137
+ else
138
+ raise ArgumentError, "signing not supported for public keys"
139
+ end
140
+ end
141
+
142
+ def verify(message, digest_type, signature)
143
+ n = signature.bytesize.div(2)
144
+ r = OpenSSL::BN.new(signature[0..(n-1)], 2)
145
+ s = OpenSSL::BN.new(signature[n..-1], 2)
146
+ asn1_sequence = OpenSSL::ASN1::Sequence.new([
147
+ OpenSSL::ASN1::Integer.new(r),
148
+ OpenSSL::ASN1::Integer.new(s)
149
+ ])
150
+ asn1_signature = asn1_sequence.to_der
151
+ return key.dsa_verify_asn1(digest_type.digest(message), asn1_signature)
152
+ end
153
+
154
+ # API functions
155
+
156
+ def self.from_key(key)
157
+ case key
158
+ when OpenSSL::PKey::EC
159
+ return JOSE::JWK::KTY_EC.new(key), JOSE::Map[]
160
+ else
161
+ raise ArgumentError, "'key' must be a OpenSSL::PKey::EC"
162
+ end
163
+ end
164
+
165
+ def to_pem(password = nil)
166
+ return JOSE::JWK::PEM.to_binary(key, password)
167
+ end
168
+
169
+ private
170
+
171
+ def pad(bin, size)
172
+ if bin.bytesize == size
173
+ return bin
174
+ else
175
+ return pad([0x00].pack('C').concat(bin), size)
176
+ end
177
+ end
178
+
179
+ end