Class: Ccrypto::Java::RSAEngine

Inherits:
Object
  • Object
show all
Includes:
DataConversion, TR::CondUtils, TeLogger::TeLogHelper
Defined in:
lib/ccrypto/java/engines/rsa_engine.rb

Overview

RSAKeyBundle

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DataConversion

#from_b64, #from_b64_mime, #from_hex, included, #logger, #to_b64, #to_b64_mime, #to_bin, #to_hex, #to_java_bytes, #to_str

Constructor Details

#initialize(*args, &block) ⇒ RSAEngine

Returns a new instance of RSAEngine.

Raises:

  • (KeypairEngineException)


183
184
185
186
187
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 183

def initialize(*args, &block)
  @config = args.first
  raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)

end

Class Method Details

.encrypt(pubKey, val, &block) ⇒ Object

Raises:

  • (KeypairEngineException)


234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 234

def self.encrypt(pubKey, val, &block)

  raise KeypairEngineException, "Public key is required" if is_empty?(pubKey)

  prov = nil
  if block
    prov = block.call(:jce_provider)
    padding = block.call(:padding)
    digAlgo = block.call(:oaep_digest)
    mode = block.call(:mode)
  end
  padding = :oaep if is_empty?(padding)
  digAlgo = :sha256 if is_empty?(digAlgo)
  mode = :none if is_empty?(mode)

  case padding
  when :pkcs1
    teLogger.owarn "RSA with PKCS1Padding mode is vulnerable. :oeap mode recommended"
    transform = "RSA/#{mode.to_s.upcase}/PKCS1Padding"

  when :oaep
    transform = "RSA/None/OAEPWith#{digAlgo.to_s.upcase}AndMGF1Padding"

    # standardize BC vs Oracle defaults
    # https://stackoverflow.com/a/50299291/3625825
    case digAlgo
    when :sha1
      oaepSpec = javax.crypto.spec.OAEPParameterSpec.new(digAlgo.to_s.upcase, "MGF1", java.security.spec.MGF1ParameterSpec::SHA1, javax.crypto.spec.PSource::PSpecified::DEFAULT)
    when :sha224
      oaepSpec = javax.crypto.spec.OAEPParameterSpec.new(digAlgo.to_s.upcase, "MGF1", java.security.spec.MGF1ParameterSpec::SHA224, javax.crypto.spec.PSource::PSpecified::DEFAULT)
    when :sha256
      oaepSpec = javax.crypto.spec.OAEPParameterSpec.new(digAlgo.to_s.upcase, "MGF1", java.security.spec.MGF1ParameterSpec::SHA256, javax.crypto.spec.PSource::PSpecified::DEFAULT)
    when :sha384
      oaepSpec = javax.crypto.spec.OAEPParameterSpec.new(digAlgo.to_s.upcase, "MGF1", java.security.spec.MGF1ParameterSpec::SHA384, javax.crypto.spec.PSource::PSpecified::DEFAULT)
    when :sha512
      oaepSpec = javax.crypto.spec.OAEPParameterSpec.new(digAlgo.to_s.upcase, "MGF1", java.security.spec.MGF1ParameterSpec::SHA512, javax.crypto.spec.PSource::PSpecified::DEFAULT)
    else
      raise KeypairEngineException, "Unknown #{digAlgo} digest for OAEP mode"
    end

  when :no_padding
    teLogger.owarn "RSA with NoPadding mode is vulnerable. :oeap mode recommended"
    transform = "RSA/#{mode.to_s.upcase}/NoPadding"

  else
    raise KeypairEngineException, "Padding requires either :pkcs1, :no_padding or :oaep. Default is :oaep"
  end

  begin

    if prov.nil?
      teLogger.debug "Encrypt transformation #{transform} with nil provider"
      cipher = javax.crypto.Cipher.getInstance(transform)
    else
      teLogger.debug "Encrypt transformation #{transform} with provider #{prov.is_a?(String) ? prov : prov.name}"
      cipher = javax.crypto.Cipher.getInstance(transform, prov)
    end


    if oaepSpec.nil?
      teLogger.debug "Init cipher with default parameter spec"
      cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, pubKey.native_pubKey)
    else
      teLogger.debug "Init cipher with parameter spec #{oaepSpec}"
      cipher.init(javax.crypto.Cipher::ENCRYPT_MODE, pubKey.native_pubKey, oaepSpec)
    end

    if block
      # this is share with caller to ensure input data should not be longer then this size
      block.call(:max_data_size, cipher.getBlockSize)
    end

    out = java.io.ByteArrayOutputStream.new
    case val
    when java.io.InputStream
      buf = ::Java::byte[102400].new
      while((read = val.read(buf, 0, buf.length)) != nil)
        out.write(cipher.update(buf, 0, read))
      end
    else
      inDat = to_java_bytes(val)
      teLogger.debug "Encrypting #{inDat.length} bytes"
      ed = cipher.update(inDat)
      out.write(ed) if not_empty?(ed)
    end

    last = cipher.doFinal
    out.write(last) if not_empty?(last)
    #out.write(cipher.doFinal)

    out.toByteArray

  rescue Exception => ex
    raise KeypairEngineException, ex
  end

end

.supported_paramsObject



179
180
181
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 179

def self.supported_params
  [1024,2048,4096,8192]
end

.verify(pubKey, val, ssign, &block) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 218

def self.verify(pubKey, val, ssign, &block)
  if block
    pss = block.call(:pss_mode)
    pss = false if is_empty?(pss) or not is_bool?(pss)

    if pss
      verify_pss(pubKey, val, ssign, &block)
    else
      verify_typical()
    end

  else
    verify_typical(pubKey, val, ssign, &block)
  end
end

Instance Method Details

#decrypt(enc, &block) ⇒ Object

Raises:

  • (KeypairEngineException)


332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 332

def decrypt(enc, &block)

  raise KeypairEngineException, "Private key is required" if not @config.has_private_key?
  raise KeypairEngineException, "RSA private key is required. Given #{@config.private_key}" if not @config.private_key.is_a?(RSAPrivateKey)

  prov = nil
  if block
    prov = block.call(:jce_provider)
    padding = block.call(:padding)
    digAlgo = block.call(:oaep_digest)
    mode = block.call(:mode)
  end
  padding = :oaep if is_empty?(padding)
  digAlgo = :sha256 if is_empty?(digAlgo)
  mode = :none if is_empty?(mode)

  case padding
  when :pkcs1
    transform = "RSA/#{mode.to_s.upcase}/PKCS1Padding"
  when :oaep
    transform = "RSA/None/OAEPWith#{digAlgo.to_s.upcase}AndMGF1Padding"
  when :no_padding
    transform = "RSA/#{mode.to_s.upcase}/NoPadding"
  else
    raise KeypairEngineException, "Padding requires either :pkcs1, :no_padding or :oaep. Default is :oaep"
  end

  begin

    if prov.nil?
      cipher = javax.crypto.Cipher.getInstance(transform)
    else
      cipher = javax.crypto.Cipher.getInstance(transform, prov)
    end

    cipher.init(javax.crypto.Cipher::DECRYPT_MODE, @config.private_key.native_privKey)

    out = java.io.ByteArrayOutputStream.new
    case enc
    when java.io.InputStream
      buf = ::Java::byte[102400].new
      while((read = enc.read(buf, 0, buf.length)) != nil)
        out.write(cipher.update(buf,0, read))
      end
    else
      inDat = to_java_bytes(enc)
      teLogger.debug "Decrypting #{inDat.length} bytes"
      pd = cipher.update(inDat)
      out.write(pd) if not_empty?(pd)
    end

    last = cipher.doFinal
    out.write(last) if not_empty?(last)

    out.toByteArray

  rescue Exception => ex
    raise KeypairEngineException, ex
  end

end

#generate_keypair(&block) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 189

def generate_keypair(&block)
  prov = Ccrypto::Java::JCEProvider::DEFProv
  if block
    prov = block.call(:jce_provider)
  end
  prov = Ccrypto::Java::JCEProvider::DEFProv if is_empty?(prov)

  kpg = java.security.KeyPairGenerator.getInstance("RSA", prov)
  kpg.java_send :initialize, [::Java::int], @config.keysize
  kp = kpg.generate_key_pair

  RSAKeyBundle.new(kp)
end

#sign(val, &block) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/ccrypto/java/engines/rsa_engine.rb', line 203

def sign(val, &block)
  if block
    pss = block.call(:pss_mode)
    pss = false if is_empty?(pss) or not is_bool?(pss)

    if pss
      sign_pss(val, &block) 
    else
      sign_typical(val, &block)
    end
  else
    sign_typical(val,&block)
  end
end