1 package org.bouncycastle.jcajce.provider.asymmetric.rsa; 2 3 import java.io.EOFException; 4 import java.io.IOException; 5 import java.io.ObjectInputStream; 6 import java.io.ObjectOutputStream; 7 import java.io.OptionalDataException; 8 import java.math.BigInteger; 9 import java.security.interfaces.RSAPublicKey; 10 import java.security.spec.RSAPublicKeySpec; 11 12 import org.bouncycastle.asn1.DERNull; 13 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 14 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 15 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 16 import org.bouncycastle.crypto.params.RSAKeyParameters; 17 import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; 18 import org.bouncycastle.util.Strings; 19 20 public class BCRSAPublicKey 21 implements RSAPublicKey 22 { 23 private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); 24 25 static final long serialVersionUID = 2675817738516720772L; 26 27 private BigInteger modulus; 28 private BigInteger publicExponent; 29 private transient AlgorithmIdentifier algorithmIdentifier; 30 31 BCRSAPublicKey( 32 RSAKeyParameters key) 33 { 34 this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; 35 this.modulus = key.getModulus(); 36 this.publicExponent = key.getExponent(); 37 } 38 39 BCRSAPublicKey( 40 RSAPublicKeySpec spec) 41 { 42 this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; 43 this.modulus = spec.getModulus(); 44 this.publicExponent = spec.getPublicExponent(); 45 } 46 47 BCRSAPublicKey( 48 RSAPublicKey key) 49 { 50 this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; 51 this.modulus = key.getModulus(); 52 this.publicExponent = key.getPublicExponent(); 53 } 54 55 BCRSAPublicKey( 56 SubjectPublicKeyInfo info) 57 { 58 populateFromPublicKeyInfo(info); 59 } 60 61 private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info) 62 { 63 try 64 { 65 org.bouncycastle.asn1.pkcs.RSAPublicKey pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey()); 66 67 this.algorithmIdentifier = info.getAlgorithm(); 68 this.modulus = pubKey.getModulus(); 69 this.publicExponent = pubKey.getPublicExponent(); 70 } 71 catch (IOException e) 72 { 73 throw new IllegalArgumentException("invalid info structure in RSA public key"); 74 } 75 } 76 77 /** 78 * return the modulus. 79 * 80 * @return the modulus. 81 */ 82 public BigInteger getModulus() 83 { 84 return modulus; 85 } 86 87 /** 88 * return the public exponent. 89 * 90 * @return the public exponent. 91 */ 92 public BigInteger getPublicExponent() 93 { 94 return publicExponent; 95 } 96 97 public String getAlgorithm() 98 { 99 return "RSA"; 100 } 101 102 public String getFormat() 103 { 104 return "X.509"; 105 } 106 107 public byte[] getEncoded() 108 { 109 return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); 110 } 111 112 public int hashCode() 113 { 114 return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode(); 115 } 116 117 public boolean equals(Object o) 118 { 119 if (o == this) 120 { 121 return true; 122 } 123 124 if (!(o instanceof RSAPublicKey)) 125 { 126 return false; 127 } 128 129 RSAPublicKey key = (RSAPublicKey)o; 130 131 return getModulus().equals(key.getModulus()) 132 && getPublicExponent().equals(key.getPublicExponent()); 133 } 134 135 public String toString() 136 { 137 StringBuffer buf = new StringBuffer(); 138 String nl = Strings.lineSeparator(); 139 140 buf.append("RSA Public Key").append(nl); 141 buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); 142 buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); 143 144 return buf.toString(); 145 } 146 147 private void readObject( 148 ObjectInputStream in) 149 throws IOException, ClassNotFoundException 150 { 151 in.defaultReadObject(); 152 153 try 154 { 155 algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject()); 156 } 157 catch (Exception e) 158 { 159 algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; 160 } 161 } 162 163 private void writeObject( 164 ObjectOutputStream out) 165 throws IOException 166 { 167 out.defaultWriteObject(); 168 169 if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER)) 170 { 171 out.writeObject(algorithmIdentifier.getEncoded()); 172 } 173 } 174 } 175