首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >密钥存储操作失败,RSA签名并验证

密钥存储操作失败,RSA签名并验证
EN

Stack Overflow用户
提问于 2018-03-21 15:37:24
回答 1查看 2.4K关注 0票数 1

我很难使用RSA进行签名和验证。下面是我使用的RSA类的一部分。方法init()privateKey()publicKey()可以很好地处理encrypt()decrypt()方法(这里没有列出最后两个方法),所以我想我在sign()方法中犯了一些错误。方法verify()还没有测试,因为签名不成功,所以我无法更进一步。请看一下..。

我的RSA课程是:

代码语言:javascript
复制
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;
代码语言:javascript
复制
    public enum KeySize
    {
        BIT_512  ( 512),
        BIT_768  ( 768),
        BIT_1024 (1024),
        BIT_2048 (2048),
        BIT_3072 (3072),
        BIT_4096 (4096);

        private int value;

        KeySize(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }
代码语言:javascript
复制
    public enum SignatureAlgorithm
    {
        MD5WithRSA        ("MD5WithRSA"),
        SHA1WithRSA       ("SHA1WithRSA"),
        SHA1WithRSA_PSS   ("SHA1WithRSA/PSS"),
        SHA224WithRSA     ("SHA224WithRSA"),
        SHA224WithRSA_PSS ("SHA224WithRSA/PSS"),
        SHA256WithRSA     ("SHA256WithRSA"),
        SHA256WithRSA_PSS ("SHA256WithRSA/PSS"),
        SHA384WithRSA     ("SHA384WithRSA"),
        SHA384WithRSA_PSS ("SHA384WithRSA/PSS"),
        SHA512WithRSA     ("SHA512WithRSA"),
        SHA512WithRSA_PSS ("SHA512WithRSA/PSS");

        private String value;

        SignatureAlgorithm(String value)
        {
            this.value = value;
        }

        public String value()
        {
            return this.value;
        }
    }
代码语言:javascript
复制
    public static KeyPair init(final String alias, final RSA.KeySize keySize, 
                final long validityDays, final Boolean reset)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, 
            IOException, NoSuchProviderException, InvalidAlgorithmParameterException
    {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
        keyStore.load(null);
        if (reset || (!keyStore.containsAlias(alias)))
        {
            final long now = java.lang.System.currentTimeMillis();
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE);
            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)
                    .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());
            return keyPairGenerator.generateKeyPair();
        }
        else return null;
    }
代码语言:javascript
复制
    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();
    }
代码语言:javascript
复制
    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);
    }
代码语言:javascript
复制
    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();
    }
代码语言:javascript
复制
    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);
    }
}

我的Hex课程是:

代码语言:javascript
复制
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);
    }
}

我的测试代码是:

代码语言:javascript
复制
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());
}

产出如下:

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

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

我的代码有什么问题?

EN

回答 1

Stack Overflow用户

发布于 2018-03-21 18:59:51

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

代码语言:javascript
复制
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)

例如:

代码语言:javascript
复制
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());

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

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

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49410575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档