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