我在寫一個用USB證書(智能卡)加密和簽名的Java程序。我有一個共享庫(在Windows上是.dll,在Linux上是.so),它爲硬件實現了PKCS11。用USB證書加密的Java(智能卡)
我正在尋找現有的解決方案,並找到以下指南http://docs.oracle.com/javase/7/docs/technotes/guides/security/p11guide.html本指南建議使用sun.security.pkcs11.SunPKCS11提供程序。
但是,我有sun.security.pkcs11包的主要問題。我設法做了簽名工作,但我無法進行加密/解密。我正在搜索,發現開發人員不應該使用'太陽'包http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html
現在,我想知道我應該用什麼來代替sun.security.pkcs11?
我有一個工作的C++代碼(使用NSS庫來處理硬件)。我發現,NSS庫正在使用C_WrapKey和C_UnwrapKey進行加密。
下面的代碼也許應該使用C_WrapKey和C_UnwrapKey爲encrption,但我可以在Java代碼中調用C_DecryptInit的.so庫由於某種原因失敗的日誌中看到(C_DecryptInit()初始化操作失敗。)。
注意:兩者(Cipher.PUBLIC_KEY/Cipher.PRIVATE_KEY和Cipher.WRAP_MODE/Cipher.UNWRAP_MODE均可在軟證書上正常工作)。該代碼僅適用於Java 1.7(Windows計算機上的32位Java)的硬核證書。
堆棧跟蹤:
Exception in thread "main" java.security.InvalidKeyException: init() failed
at sun.security.pkcs11.P11RSACipher.implInit(P11RSACipher.java:239)
at sun.security.pkcs11.P11RSACipher.engineUnwrap(P11RSACipher.java:479)
at javax.crypto.Cipher.unwrap(Cipher.java:2510)
at gem_test.Test.decryptDocument(Test.java:129)
at gem_test.Test.main(Test.java:81)
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_KEY_FUNCTION_NOT_PERMITTED
at sun.security.pkcs11.wrapper.PKCS11.C_DecryptInit(Native Method)
at sun.security.pkcs11.P11RSACipher.initialize(P11RSACipher.java:304)
at sun.security.pkcs11.P11RSACipher.implInit(P11RSACipher.java:237)
... 4 more
代碼:
package gem_test;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import sun.security.pkcs11.SunPKCS11;
public class Test {
private static final String ALGORITHM = "RSA";
static int hard_soft = 1; // 1 - smart card, 2 - soft certificate
static int sign_encrypt = 2; // 1- sign, 2 - encryption
public static void main(String[] args) throws Exception {
PrivateKey privateKey;
PublicKey pubKey;
if (hard_soft == 1) {
String pkcsConf = (
"name = Personal\n" +
"library = /usr/local/lib/personal/libP11.so\n" +
// "library = c:\\perso\\bin\\personal.dll\n" +
"slot = 0\n"
);
char[] pin = "123456".toCharArray();
String useCertAlias = "Digital Signature";
// String useCertAlias = "Non Repudiation";
SunPKCS11 provider = new SunPKCS11(new ByteArrayInputStream(pkcsConf.getBytes()));
String providerName = provider.getName();
Security.addProvider(provider);
KeyStore keyStore = KeyStore.getInstance("PKCS11", providerName);
keyStore.load(null, pin);
privateKey = (PrivateKey) keyStore.getKey(useCertAlias, pin);
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(useCertAlias);
pubKey = certificate.getPublicKey();
} else if (hard_soft == 2) {
/*
mkdir /tmp/softkey
cd /tmp/softkey
openssl genrsa 2048 > softkey.key
chmod 400 softkey.key
openssl req -new -x509 -nodes -sha1 -days 365 -key softkey.key -out softkey.crt
openssl pkcs12 -export -in softkey.crt -inkey softkey.key -out softkey.pfx
rm -f softkey.key softkey.crt
*/
String pfx = "/tmp/softkey/softkey.pfx";
String useCertAlias = "1";
KeyStore keyStore1 = KeyStore.getInstance("PKCS12");
keyStore1.load(new FileInputStream(pfx), new char[]{});
privateKey = (PrivateKey) keyStore1.getKey(useCertAlias, new char[]{});
X509Certificate certificate = (X509Certificate) keyStore1.getCertificate(useCertAlias);
pubKey = certificate.getPublicKey();
} else {
throw new IllegalStateException();
}
if (sign_encrypt == 1) {
byte[] sig = signDocument("msg content".getBytes(), privateKey);
boolean result = verifyDocument("msg content".getBytes(), sig, pubKey);
System.out.println("RESULT " + result);
} else if (sign_encrypt == 2) {
byte[] encrypted = encryptDocument("msg content".getBytes(), pubKey);
byte[] decryptedDocument = decryptDocument(encrypted, privateKey);
System.out.println("RESULT " + new String(decryptedDocument));
} else {
throw new IllegalStateException();
}
}
private static byte[] signDocument(byte[] aDocument, PrivateKey aPrivateKey) throws Exception {
Signature signatureAlgorithm = Signature.getInstance("SHA1withRSA");
signatureAlgorithm.initSign(aPrivateKey);
signatureAlgorithm.update(aDocument);
byte[] digitalSignature = signatureAlgorithm.sign();
return digitalSignature;
}
private static boolean verifyDocument(byte[] aDocument, byte[] sig, PublicKey pubKey) throws Exception {
Signature signatureAlgorithm = Signature.getInstance("SHA1withRSA");
signatureAlgorithm.initVerify(pubKey);
signatureAlgorithm.update(aDocument);
return signatureAlgorithm.verify(sig);
}
private static byte[] encryptDocument(byte[] aDocument, PublicKey pubKey) throws Exception {
int encrypt_wrap = 2;
if (encrypt_wrap == 1) {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.PUBLIC_KEY, pubKey);
return cipher.doFinal(aDocument);
} else if (encrypt_wrap == 2) {
SecretKey data = new SecretKeySpec(aDocument, 0, aDocument.length, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.WRAP_MODE, pubKey);
return cipher.wrap(data);
} else {
throw new IllegalStateException();
}
}
public static byte[] decryptDocument(byte[] encryptedDocument, PrivateKey aPrivateKey) throws Exception {
int encrypt_wrap = 2;
if (encrypt_wrap == 1) {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.PRIVATE_KEY, aPrivateKey);
return cipher.doFinal(encryptedDocument);
} else if (encrypt_wrap == 2) {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.UNWRAP_MODE, aPrivateKey);
SecretKey res = (SecretKey) cipher.unwrap(encryptedDocument, "AES", Cipher.SECRET_KEY);
return res.getEncoded();
} else {
throw new IllegalStateException();
}
}
}
可能與(或重複)[PKCS11Exception:CKR_KEY_FUNCTION_NOT_PERMITTED](https://stackoverflow.com/questions/8887218/pkcs11exception-ckr - 關鍵功能不允許) –
謝謝@ M.Prokhorov:我看到了這個。我有一個C++和NSS庫的工作解決方案,所以硬件(智能卡)應該工作。 – Predkambrij
那麼,你的異常記錄爲「試圖將密鑰用於密鑰的目的,該密鑰的屬性未設置爲允許它執行」。你確定你的java實現使用你的庫嗎?如果是這樣,也許在某處添加一些日誌語句,並檢查所有值是否正確傳遞。 –