4040import java .security .NoSuchAlgorithmException ;
4141import java .security .PrivateKey ;
4242import java .security .PublicKey ;
43- import java .security .SecureRandom ;
4443import java .security .interfaces .RSAPrivateCrtKey ;
44+ import java .security .interfaces .RSAPrivateKey ;
4545import java .security .interfaces .RSAPublicKey ;
4646import java .security .spec .InvalidKeySpecException ;
4747import java .security .spec .RSAKeyGenParameterSpec ;
4848import java .security .spec .RSAPrivateCrtKeySpec ;
49+ import java .security .spec .RSAPrivateKeySpec ;
4950import java .security .spec .RSAPublicKeySpec ;
5051
5152import static javax .crypto .Cipher .*;
@@ -108,7 +109,11 @@ public static RaiseException newRSAError(Ruby runtime, String message) {
108109 }
109110
110111 static RaiseException newRSAError (Ruby runtime , Throwable cause ) {
111- return Utils .newError (runtime , _PKey (runtime ).getClass ("RSAError" ), cause .getMessage (), cause );
112+ return newRSAError (runtime , cause .getMessage (), cause );
113+ }
114+
115+ static RaiseException newRSAError (Ruby runtime , String message , Throwable cause ) {
116+ return Utils .newError (runtime , _PKey (runtime ).getClass ("RSAError" ), message , cause );
112117 }
113118
114119 public PKeyRSA (Ruby runtime , RubyClass type ) {
@@ -126,7 +131,7 @@ public PKeyRSA(Ruby runtime, RubyClass type, RSAPrivateCrtKey privKey, RSAPublic
126131 }
127132
128133 private volatile RSAPublicKey publicKey ;
129- private volatile transient RSAPrivateCrtKey privateKey ;
134+ private volatile transient RSAPrivateKey privateKey ;
130135
131136 // fields to hold individual RSAPublicKeySpec components. this allows
132137 // a public key to be constructed incrementally, as required by the
@@ -317,8 +322,9 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a
317322 }
318323 else if ( key instanceof RSAPrivateCrtKey ) {
319324 this .privateKey = (RSAPrivateCrtKey ) key ;
325+ BigInteger exponent = ((RSAPrivateCrtKey ) key ).getPublicExponent ();
320326 try {
321- this .publicKey = (RSAPublicKey ) rsaFactory .generatePublic (new RSAPublicKeySpec (privateKey .getModulus (), privateKey . getPublicExponent () ));
327+ this .publicKey = (RSAPublicKey ) rsaFactory .generatePublic (new RSAPublicKeySpec (privateKey .getModulus (), exponent ));
322328 } catch (GeneralSecurityException e ) {
323329 throw newRSAError (runtime , e .getMessage ());
324330 } catch (RuntimeException e ) {
@@ -355,7 +361,7 @@ public RubyBoolean private_p() {
355361 public RubyString to_der () {
356362 final byte [] bytes ;
357363 try {
358- bytes = toDerRSAKey (publicKey , privateKey );
364+ bytes = toDerRSAKey (publicKey , privateKey instanceof RSAPrivateCrtKey ? ( RSAPrivateCrtKey ) privateKey : null );
359365 }
360366 catch (NoClassDefFoundError e ) {
361367 throw newRSAError (getRuntime (), bcExceptionMessage (e ));
@@ -380,7 +386,8 @@ public PKeyRSA public_key() {
380386 public IRubyObject params (final ThreadContext context ) {
381387 final Ruby runtime = context .runtime ;
382388 RubyHash hash = RubyHash .newHash (runtime );
383- if ( privateKey != null ) {
389+ if (privateKey instanceof RSAPrivateCrtKey ) {
390+ RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey ) this .privateKey ;
384391 hash .op_aset (context , runtime .newString ("iqmp" ), BN .newBN (runtime , privateKey .getCrtCoefficient ()));
385392 hash .op_aset (context , runtime .newString ("n" ), BN .newBN (runtime , privateKey .getModulus ()));
386393 hash .op_aset (context , runtime .newString ("d" ), BN .newBN (runtime , privateKey .getPrivateExponent ()));
@@ -406,7 +413,8 @@ public IRubyObject params(final ThreadContext context) {
406413 @ JRubyMethod
407414 public RubyString to_text () {
408415 StringBuilder result = new StringBuilder ();
409- if (privateKey != null ) {
416+ if (privateKey instanceof RSAPrivateCrtKey ) {
417+ RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey ) this .privateKey ;
410418 int len = privateKey .getModulus ().bitLength ();
411419 result .append ("Private-Key: (" ).append (len ).append (" bit)" ).append ('\n' );
412420 result .append ("modulus:" );
@@ -446,8 +454,8 @@ public RubyString to_pem(ThreadContext context, final IRubyObject[] args) {
446454
447455 try {
448456 final StringWriter writer = new StringWriter ();
449- if ( privateKey != null ) {
450- PEMInputOutput .writeRSAPrivateKey (writer , privateKey , spec , passwd );
457+ if (privateKey instanceof RSAPrivateCrtKey ) {
458+ PEMInputOutput .writeRSAPrivateKey (writer , ( RSAPrivateCrtKey ) privateKey , spec , passwd );
451459 }
452460 else {
453461 PEMInputOutput .writeRSAPublicKey (writer , publicKey );
@@ -603,8 +611,8 @@ public synchronized IRubyObject set_iqmp(final ThreadContext context, IRubyObjec
603611 @ JRubyMethod (name ="iqmp" )
604612 public synchronized IRubyObject get_iqmp () {
605613 BigInteger iqmp ;
606- if (privateKey != null ) {
607- iqmp = privateKey .getCrtCoefficient ();
614+ if (privateKey instanceof RSAPrivateCrtKey ) {
615+ iqmp = (( RSAPrivateCrtKey ) privateKey ) .getCrtCoefficient ();
608616 } else {
609617 iqmp = rsa_iqmp ;
610618 }
@@ -617,8 +625,8 @@ public synchronized IRubyObject get_iqmp() {
617625 @ JRubyMethod (name ="dmp1" )
618626 public synchronized IRubyObject get_dmp1 () {
619627 BigInteger dmp1 ;
620- if (privateKey != null ) {
621- dmp1 = privateKey .getPrimeExponentP ();
628+ if (privateKey instanceof RSAPrivateCrtKey ) {
629+ dmp1 = (( RSAPrivateCrtKey ) privateKey ) .getPrimeExponentP ();
622630 } else {
623631 dmp1 = rsa_dmp1 ;
624632 }
@@ -631,8 +639,8 @@ public synchronized IRubyObject get_dmp1() {
631639 @ JRubyMethod (name ="dmq1" )
632640 public synchronized IRubyObject get_dmq1 () {
633641 BigInteger dmq1 ;
634- if (privateKey != null ) {
635- dmq1 = privateKey .getPrimeExponentQ ();
642+ if (privateKey instanceof RSAPrivateCrtKey ) {
643+ dmq1 = (( RSAPrivateCrtKey ) privateKey ) .getPrimeExponentQ ();
636644 } else {
637645 dmq1 = rsa_dmq1 ;
638646 }
@@ -659,8 +667,8 @@ public synchronized IRubyObject get_d() {
659667 @ JRubyMethod (name ="p" )
660668 public synchronized IRubyObject get_p () {
661669 BigInteger p ;
662- if (privateKey != null ) {
663- p = privateKey .getPrimeP ();
670+ if (privateKey instanceof RSAPrivateCrtKey ) {
671+ p = (( RSAPrivateCrtKey ) privateKey ) .getPrimeP ();
664672 } else {
665673 p = rsa_p ;
666674 }
@@ -673,8 +681,8 @@ public synchronized IRubyObject get_p() {
673681 @ JRubyMethod (name ="q" )
674682 public synchronized IRubyObject get_q () {
675683 BigInteger q ;
676- if (privateKey != null ) {
677- q = privateKey .getPrimeQ ();
684+ if (privateKey instanceof RSAPrivateCrtKey ) {
685+ q = (( RSAPrivateCrtKey ) privateKey ) .getPrimeQ ();
678686 } else {
679687 q = rsa_q ;
680688 }
@@ -687,8 +695,8 @@ public synchronized IRubyObject get_q() {
687695 private BigInteger getPublicExponent () {
688696 if (publicKey != null ) {
689697 return publicKey .getPublicExponent ();
690- } else if (privateKey != null ) {
691- return privateKey .getPublicExponent ();
698+ } else if (privateKey instanceof RSAPrivateCrtKey ) {
699+ return (( RSAPrivateCrtKey ) privateKey ) .getPublicExponent ();
692700 } else {
693701 return rsa_e ;
694702 }
@@ -750,6 +758,32 @@ public synchronized IRubyObject set_n(final ThreadContext context, IRubyObject v
750758 return value ;
751759 }
752760
761+ @ JRubyMethod
762+ public IRubyObject set_key (final ThreadContext context , IRubyObject n , IRubyObject e , IRubyObject d ) {
763+ this .rsa_n = BN .getBigInteger (n );
764+ this .rsa_e = BN .getBigInteger (e );
765+ this .rsa_d = BN .getBigInteger (d );
766+ generatePrivateKeyIfParams (context );
767+ return this ;
768+ }
769+
770+ @ JRubyMethod
771+ public IRubyObject set_factors (final ThreadContext context , IRubyObject p , IRubyObject q ) {
772+ this .rsa_p = BN .getBigInteger (p );
773+ this .rsa_q = BN .getBigInteger (q );
774+ generatePrivateKeyIfParams (context );
775+ return this ;
776+ }
777+
778+ @ JRubyMethod
779+ public IRubyObject set_crt_params (final ThreadContext context , IRubyObject dmp1 , IRubyObject dmq1 , IRubyObject iqmp ) {
780+ this .rsa_dmp1 = BN .asBigInteger (dmp1 );
781+ this .rsa_dmq1 = BN .asBigInteger (dmq1 );
782+ this .rsa_iqmp = BN .asBigInteger (iqmp );
783+ generatePrivateKeyIfParams (context );
784+ return this ;
785+ }
786+
753787 private void generatePublicKeyIfParams (final ThreadContext context ) {
754788 final Ruby runtime = context .runtime ;
755789
@@ -783,14 +817,12 @@ private void generatePublicKeyIfParams(final ThreadContext context) {
783817 private void generatePrivateKeyIfParams (final ThreadContext context ) {
784818 final Ruby runtime = context .runtime ;
785819
786- if ( privateKey != null ) throw newRSAError (runtime , "illegal modification" );
787-
788820 // Don't access the rsa_n and rsa_e fields directly. They may have
789821 // already been consumed and cleared by generatePublicKeyIfParams.
790822 BigInteger _rsa_n = getModulus ();
791823 BigInteger _rsa_e = getPublicExponent ();
792824
793- if (_rsa_n != null && _rsa_e != null && rsa_p != null && rsa_q != null && rsa_d != null && rsa_dmp1 != null && rsa_dmq1 != null && rsa_iqmp != null ) {
825+ if (_rsa_n != null && _rsa_e != null && rsa_d != null ) {
794826 final KeyFactory rsaFactory ;
795827 try {
796828 rsaFactory = SecurityHelper .getKeyFactory ("RSA" );
@@ -799,17 +831,24 @@ private void generatePrivateKeyIfParams(final ThreadContext context) {
799831 throw runtime .newLoadError ("unsupported key algorithm (RSA)" );
800832 }
801833
802- try {
803- privateKey = (RSAPrivateCrtKey ) rsaFactory .generatePrivate (
804- new RSAPrivateCrtKeySpec (_rsa_n , _rsa_e , rsa_d , rsa_p , rsa_q , rsa_dmp1 , rsa_dmq1 , rsa_iqmp )
805- );
806- }
807- catch (InvalidKeySpecException e ) {
808- throw newRSAError (runtime , "invalid parameters" );
834+ if (rsa_p != null && rsa_q != null && rsa_dmp1 != null && rsa_dmq1 != null && rsa_iqmp != null ) {
835+ try {
836+ privateKey = (RSAPrivateCrtKey ) rsaFactory .generatePrivate (
837+ new RSAPrivateCrtKeySpec (_rsa_n , _rsa_e , rsa_d , rsa_p , rsa_q , rsa_dmp1 , rsa_dmq1 , rsa_iqmp )
838+ );
839+ } catch (InvalidKeySpecException e ) {
840+ throw newRSAError (runtime , "invalid parameters" , e );
841+ }
842+ rsa_n = null ; rsa_e = null ; rsa_d = null ;
843+ rsa_p = null ; rsa_q = null ;
844+ rsa_dmp1 = null ; rsa_dmq1 = null ; rsa_iqmp = null ;
845+ } else {
846+ try {
847+ privateKey = (RSAPrivateKey ) rsaFactory .generatePrivate (new RSAPrivateKeySpec (_rsa_n , rsa_d ));
848+ } catch (InvalidKeySpecException e ) {
849+ throw newRSAError (runtime , "invalid parameters" , e );
850+ }
809851 }
810- rsa_n = null ; rsa_e = null ;
811- rsa_d = null ; rsa_p = null ; rsa_q = null ;
812- rsa_dmp1 = null ; rsa_dmq1 = null ; rsa_iqmp = null ;
813852 }
814853 }
815854
0 commit comments