Java 密钥库操作失败,RSA签名并验证
我很难使用RSA进行签名和验证。下面是我使用的RSA类的一部分。init、privateKey和publicKey方法与加密和解密方法配合使用效果很好,这里没有列出最后两种方法,因此我假设我在sign方法中犯了一些错误。方法验证尚未测试,因为签名未成功,所以我无法进一步移动。请看一看 我的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
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());