1 package org.bouncycastle.jcajce.provider.asymmetric.rsa; 2 3 import java.io.IOException; 4 import java.security.AlgorithmParameters; 5 import java.security.InvalidKeyException; 6 import java.security.PrivateKey; 7 import java.security.PublicKey; 8 import java.security.SignatureException; 9 import java.security.SignatureSpi; 10 import java.security.interfaces.RSAPrivateKey; 11 import java.security.interfaces.RSAPublicKey; 12 import java.security.spec.AlgorithmParameterSpec; 13 14 import org.bouncycastle.asn1.ASN1Encoding; 15 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 16 import org.bouncycastle.asn1.DERNull; 17 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; 18 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; 19 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 20 // BEGIN android-removed 21 // import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; 22 // END android-removed 23 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 24 import org.bouncycastle.asn1.x509.DigestInfo; 25 import org.bouncycastle.crypto.AsymmetricBlockCipher; 26 import org.bouncycastle.crypto.CipherParameters; 27 import org.bouncycastle.crypto.Digest; 28 // BEGIN android-removed 29 // import org.bouncycastle.crypto.digests.MD2Digest; 30 // import org.bouncycastle.crypto.digests.MD4Digest; 31 // import org.bouncycastle.crypto.digests.MD5Digest; 32 // import org.bouncycastle.crypto.digests.NullDigest; 33 // import org.bouncycastle.crypto.digests.RIPEMD128Digest; 34 // import org.bouncycastle.crypto.digests.RIPEMD160Digest; 35 // import org.bouncycastle.crypto.digests.RIPEMD256Digest; 36 // import org.bouncycastle.crypto.digests.SHA1Digest; 37 // import org.bouncycastle.crypto.digests.SHA224Digest; 38 // import org.bouncycastle.crypto.digests.SHA256Digest; 39 // import org.bouncycastle.crypto.digests.SHA384Digest; 40 // import org.bouncycastle.crypto.digests.SHA512Digest; 41 // END android-removed 42 // BEGIN android-added 43 import org.bouncycastle.crypto.digests.AndroidDigestFactory; 44 // END android-added 45 import org.bouncycastle.crypto.encodings.PKCS1Encoding; 46 import org.bouncycastle.crypto.engines.RSABlindedEngine; 47 48 public class DigestSignatureSpi 49 extends SignatureSpi 50 { 51 private Digest digest; 52 private AsymmetricBlockCipher cipher; 53 private AlgorithmIdentifier algId; 54 55 // care - this constructor is actually used by outside organisations 56 protected DigestSignatureSpi( 57 Digest digest, 58 AsymmetricBlockCipher cipher) 59 { 60 this.digest = digest; 61 this.cipher = cipher; 62 this.algId = null; 63 } 64 65 // care - this constructor is actually used by outside organisations 66 protected DigestSignatureSpi( 67 ASN1ObjectIdentifier objId, 68 Digest digest, 69 AsymmetricBlockCipher cipher) 70 { 71 this.digest = digest; 72 this.cipher = cipher; 73 this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE); 74 } 75 76 protected void engineInitVerify( 77 PublicKey publicKey) 78 throws InvalidKeyException 79 { 80 if (!(publicKey instanceof RSAPublicKey)) 81 { 82 throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance"); 83 } 84 85 CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey); 86 87 digest.reset(); 88 cipher.init(false, param); 89 } 90 91 protected void engineInitSign( 92 PrivateKey privateKey) 93 throws InvalidKeyException 94 { 95 if (!(privateKey instanceof RSAPrivateKey)) 96 { 97 throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance"); 98 } 99 100 CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey); 101 102 digest.reset(); 103 104 cipher.init(true, param); 105 } 106 107 private String getType( 108 Object o) 109 { 110 if (o == null) 111 { 112 return null; 113 } 114 115 return o.getClass().getName(); 116 } 117 118 protected void engineUpdate( 119 byte b) 120 throws SignatureException 121 { 122 digest.update(b); 123 } 124 125 protected void engineUpdate( 126 byte[] b, 127 int off, 128 int len) 129 throws SignatureException 130 { 131 digest.update(b, off, len); 132 } 133 134 protected byte[] engineSign() 135 throws SignatureException 136 { 137 byte[] hash = new byte[digest.getDigestSize()]; 138 139 digest.doFinal(hash, 0); 140 141 try 142 { 143 byte[] bytes = derEncode(hash); 144 145 return cipher.processBlock(bytes, 0, bytes.length); 146 } 147 catch (ArrayIndexOutOfBoundsException e) 148 { 149 throw new SignatureException("key too small for signature type"); 150 } 151 catch (Exception e) 152 { 153 throw new SignatureException(e.toString()); 154 } 155 } 156 157 protected boolean engineVerify( 158 byte[] sigBytes) 159 throws SignatureException 160 { 161 byte[] hash = new byte[digest.getDigestSize()]; 162 163 digest.doFinal(hash, 0); 164 165 byte[] sig; 166 byte[] expected; 167 168 try 169 { 170 sig = cipher.processBlock(sigBytes, 0, sigBytes.length); 171 172 expected = derEncode(hash); 173 } 174 catch (Exception e) 175 { 176 return false; 177 } 178 179 if (sig.length == expected.length) 180 { 181 for (int i = 0; i < sig.length; i++) 182 { 183 if (sig[i] != expected[i]) 184 { 185 return false; 186 } 187 } 188 } 189 else if (sig.length == expected.length - 2) // NULL left out 190 { 191 int sigOffset = sig.length - hash.length - 2; 192 int expectedOffset = expected.length - hash.length - 2; 193 194 expected[1] -= 2; // adjust lengths 195 expected[3] -= 2; 196 197 for (int i = 0; i < hash.length; i++) 198 { 199 if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash 200 { 201 return false; 202 } 203 } 204 205 for (int i = 0; i < sigOffset; i++) 206 { 207 if (sig[i] != expected[i]) // check header less NULL 208 { 209 return false; 210 } 211 } 212 } 213 else 214 { 215 return false; 216 } 217 218 return true; 219 } 220 221 protected void engineSetParameter( 222 AlgorithmParameterSpec params) 223 { 224 throw new UnsupportedOperationException("engineSetParameter unsupported"); 225 } 226 227 /** 228 * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"> 229 */ 230 protected void engineSetParameter( 231 String param, 232 Object value) 233 { 234 throw new UnsupportedOperationException("engineSetParameter unsupported"); 235 } 236 237 /** 238 * @deprecated 239 */ 240 protected Object engineGetParameter( 241 String param) 242 { 243 return null; 244 } 245 246 protected AlgorithmParameters engineGetParameters() 247 { 248 return null; 249 } 250 251 private byte[] derEncode( 252 byte[] hash) 253 throws IOException 254 { 255 if (algId == null) 256 { 257 // For raw RSA, the DigestInfo must be prepared externally 258 return hash; 259 } 260 261 DigestInfo dInfo = new DigestInfo(algId, hash); 262 263 return dInfo.getEncoded(ASN1Encoding.DER); 264 } 265 266 static public class SHA1 267 extends DigestSignatureSpi 268 { 269 public SHA1() 270 { 271 // BEGIN android-changed 272 super(OIWObjectIdentifiers.idSHA1, AndroidDigestFactory.getSHA1(), new PKCS1Encoding(new RSABlindedEngine())); 273 // END android-changed 274 } 275 } 276 277 // BEGIN android-removed 278 // static public class SHA224 279 // extends DigestSignatureSpi 280 // { 281 // public SHA224() 282 // { 283 // super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine())); 284 // } 285 // } 286 // END android-removed 287 288 static public class SHA256 289 extends DigestSignatureSpi 290 { 291 public SHA256() 292 { 293 // BEGIN android-changed 294 super(NISTObjectIdentifiers.id_sha256, AndroidDigestFactory.getSHA256(), new PKCS1Encoding(new RSABlindedEngine())); 295 // END android-changed 296 } 297 } 298 299 static public class SHA384 300 extends DigestSignatureSpi 301 { 302 public SHA384() 303 { 304 // BEGIN android-changed 305 super(NISTObjectIdentifiers.id_sha384, AndroidDigestFactory.getSHA384(), new PKCS1Encoding(new RSABlindedEngine())); 306 // END android-changed 307 } 308 } 309 310 static public class SHA512 311 extends DigestSignatureSpi 312 { 313 public SHA512() 314 { 315 // BEGIN android-changed 316 super(NISTObjectIdentifiers.id_sha512, AndroidDigestFactory.getSHA512(), new PKCS1Encoding(new RSABlindedEngine())); 317 // END android-changed 318 } 319 } 320 321 // BEGIN android-removed 322 // static public class MD2 323 // extends DigestSignatureSpi 324 // { 325 // public MD2() 326 // { 327 // super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine())); 328 // } 329 // } 330 // 331 // static public class MD4 332 // extends DigestSignatureSpi 333 // { 334 // public MD4() 335 // { 336 // super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine())); 337 // } 338 // } 339 // END android-removed 340 341 static public class MD5 342 extends DigestSignatureSpi 343 { 344 public MD5() 345 { 346 // BEGIN android-changed 347 super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine())); 348 // END android-changed 349 } 350 } 351 352 // BEGIN android-removed 353 // static public class RIPEMD160 354 // extends DigestSignatureSpi 355 // { 356 // public RIPEMD160() 357 // { 358 // super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine())); 359 // } 360 // } 361 // 362 // static public class RIPEMD128 363 // extends DigestSignatureSpi 364 // { 365 // public RIPEMD128() 366 // { 367 // super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine())); 368 // } 369 // } 370 // 371 // static public class RIPEMD256 372 // extends DigestSignatureSpi 373 // { 374 // public RIPEMD256() 375 // { 376 // super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine())); 377 // } 378 // } 379 // 380 // static public class noneRSA 381 // extends DigestSignatureSpi 382 // { 383 // public noneRSA() 384 // { 385 // super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine())); 386 // } 387 // } 388 // END android-removed 389 } 390