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 // 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