Java 密钥库操作失败,RSA签名并验证

Java 密钥库操作失败,RSA签名并验证,java,android,encryption,cryptography,rsa,Java,Android,Encryption,Cryptography,Rsa,我很难使用RSA进行签名和验证。下面是我使用的RSA类的一部分。init、privateKey和publicKey方法与加密和解密方法配合使用效果很好,这里没有列出最后两种方法,因此我假设我在sign方法中犯了一些错误。方法验证尚未测试,因为签名未成功,所以我无法进一步移动。请看一看 我的RSA课程是: class RSA { private final static String ANDROID_KEY_STORE = "AndroidKeyStore"; public fi

我很难使用RSA进行签名和验证。下面是我使用的RSA类的一部分。init、privateKey和publicKey方法与加密和解密方法配合使用效果很好,这里没有列出最后两种方法,因此我假设我在sign方法中犯了一些错误。方法验证尚未测试,因为签名未成功,所以我无法进一步移动。请看一看

我的RSA课程是:

class RSA
{
    private final static String ANDROID_KEY_STORE = "AndroidKeyStore";

    public final static int ANY_PURPOSE = KeyProperties.PURPOSE_ENCRYPT | 
            KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN | 
            KeyProperties.PURPOSE_VERIFY;

    public final static long CENTURY = (100 * 365) + 24;
class Hex
{
    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHexString(final byte[] bytes)
    {
        char[] hexChars = new char[2 * bytes.length];
        for (int i = 0; i < bytes.length; i++)
        {
            int b = bytes[i] & 0xFF;
            hexChars[2 * i] = hexArray[b >>> 4];
            hexChars[2 * i + 1] = hexArray[b & 0x0F];
        }
        return new String(hexChars);
    }
}
我的十六进制类是:

class RSA
{
    private final static String ANDROID_KEY_STORE = "AndroidKeyStore";

    public final static int ANY_PURPOSE = KeyProperties.PURPOSE_ENCRYPT | 
            KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN | 
            KeyProperties.PURPOSE_VERIFY;

    public final static long CENTURY = (100 * 365) + 24;
class Hex
{
    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHexString(final byte[] bytes)
    {
        char[] hexChars = new char[2 * bytes.length];
        for (int i = 0; i < bytes.length; i++)
        {
            int b = bytes[i] & 0xFF;
            hexChars[2 * i] = hexArray[b >>> 4];
            hexChars[2 * i + 1] = hexArray[b & 0x0F];
        }
        return new String(hexChars);
    }
}
输出为:

错误:java.security.InvalidKeyException:密钥库操作失败

调试表明,当我的RSA.sign方法调用initSign时,错误发生在该方法内部


我的代码有什么问题

如果使用RSA密钥签名,则必须在中设置签名填充模式。你还没有这样做。例如,在init方法中,可以在.setEncryptionPaddings之后添加以下行:

e、 g

另一种受支持的签名填充模式是签名填充RSA PSS。请注意,PSS签名和OAEP加密是用于签名和加密的RSA块格式的更现代版本。它们提供了更好的安全保证,并且应该始终优先于其他模式,除非由于与现有代码库的互操作性问题而无法使用它们


以PSS结尾的签名算法名称,例如SHA224WithRSA_PSS,显然仅用于PSS填充,而其他名称仅用于PKCS1填充。

如果使用RSA密钥签名,则必须在中设置签名填充模式。你还没有这样做。例如,在init方法中,可以在.setEncryptionPaddings之后添加以下行:

e、 g

另一种受支持的签名填充模式是签名填充RSA PSS。请注意,PSS签名和OAEP加密是用于签名和加密的RSA块格式的更现代版本。它们提供了更好的安全保证,并且应该始终优先于其他模式,除非由于与现有代码库的互操作性问题而无法使用它们


以PSS结尾的签名算法名称,例如SHA224WithRSA_PSS,显然仅用于PSS填充,而其他名称仅用于PKCS1填充。

我在代码中没有看到任何明显的错误,但有时使用太多参数初始化androidkeystore会有问题。您能将密钥生成器的初始化限制为数字签名参数吗?@pedrofb-我尝试过,但这种限制没有改变任何东西。我看不到您的代码中有任何明显的错误,但有时参数过多的androidkeystore的初始化是有问题的。您能将keyPairGenerator的初始化限制为数字签名参数吗?@pedrofb-我尝试过,但这种限制没有改变任何东西。您是对的,.setSignaturePaddings是我没有的,这会有所不同。一旦我把它添加到我的代码中,它就可以工作了!谢谢我发现除了签名填充RSA PKCS1之外,这个设置还有签名填充RSA PSS选项。请您在回答中补充解释和澄清这两种设置之间的差异,以及其中任何设置是否仅限于在我的类中RSA.SignatureAlgorithm enum下定义的签名算法集。非常感谢。你是对的,.setSignaturePaddings是我没有的,这很重要。一旦我把它添加到我的代码中,它就可以工作了!谢谢我发现除了签名填充RSA PKCS1之外,这个设置还有签名填充RSA PSS选项。请您在回答中补充解释和澄清这两种设置之间的差异,以及其中任何设置是否仅限于在我的类中RSA.SignatureAlgorithm enum下定义的签名算法集。非常感谢。
    public static PublicKey publicKey(final String alias)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, 
            IOException, UnrecoverableEntryException
    {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
        keyStore.load(null);
        return keyStore.getCertificate(alias).getPublicKey();
    }
    public static PrivateKey privateKey(final String alias)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, 
            IOException, UnrecoverableEntryException
    {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
        keyStore.load(null);
        return (PrivateKey) keyStore.getKey(alias, null);
    }
    public static byte[] sign(final String message, final String alias, 
                final SignatureAlgorithm algorithm)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, 
            IOException, UnrecoverableEntryException,
            InvalidKeyException, SignatureException
    {
        Signature instance = Signature.getInstance(algorithm.value());
        instance.initSign(privateKey(alias), new SecureRandom());
        instance.update(message.getBytes("UTF-8"));
        return instance.sign();
    }
    public static Boolean verify(final String message, final byte[] signature, 
                final String alias, final SignatureAlgorithm algorithm)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, 
            IOException, UnrecoverableEntryException,
            InvalidKeyException, SignatureException
    {
        Signature instance = Signature.getInstance(algorithm.value());
        instance.initVerify(publicKey(alias));
        instance.update(message.getBytes("UTF-8"));
        return instance.verify(signature);
    }
}
class Hex
{
    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHexString(final byte[] bytes)
    {
        char[] hexChars = new char[2 * bytes.length];
        for (int i = 0; i < bytes.length; i++)
        {
            int b = bytes[i] & 0xFF;
            hexChars[2 * i] = hexArray[b >>> 4];
            hexChars[2 * i + 1] = hexArray[b & 0x0F];
        }
        return new String(hexChars);
    }
}
try
{
    RSA.init("RSA", RSA.KeySize.BIT_512, RSA.CENTURY, true);

    RSA.SignatureAlgorithm signatureAlgorithm = RSA.SignatureAlgorithm.SHA1WithRSA;

    byte[] x = RSA.sign("My message", "RSA", signatureAlgorithm);
    Log.d("RSA Test", "x: " + Hex.bytesToHexString(x));

    Boolean y = RSA.verify("My message", x, "RSA", signatureAlgorithm);
    Log.d("RSA Test", "y: " + (y? "True" : "False"));
}
catch (Exception e)
{
    Log.d("RSA Test", "ERROR: " + e.toString());
}
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
keyPairGenerator.initialize(
                    new KeyGenParameterSpec.Builder(alias, RSA.ANY_PURPOSE)
                            .setRandomizedEncryptionRequired(false)
                            .setDigests(
                                    KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_MD5,
                                    KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA224,
                                    KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384,
                                    KeyProperties.DIGEST_SHA512)
                            .setKeySize(keySize.value())
                            .setEncryptionPaddings(
                                    KeyProperties.ENCRYPTION_PADDING_NONE,
                                    KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
                                    KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
                            .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                            .setCertificateSubject(new X500Principal(
                                    "CN=Android, O=Android Authority"))
                            .setCertificateSerialNumber(new BigInteger(256, new Random()))
                            .setCertificateNotBefore(new Date(now - (now % 1000L)))
                            .setCertificateNotAfter(new Date(((new Date(now - (now % 1000L)))
                                    .getTime()) + (validityDays * 86400000L)))
                            .build());