【发布时间】:2014-05-14 00:01:00
【问题描述】:
我正在使用我在桌面应用程序上生成的公钥在 java 智能卡上加密一些数据字节,但是当我尝试解密桌面上的数据时,我得到了BadPaddingException : Data must start with zero,我读到这可能是由使用虚假私钥解密数据引起的。
-
首先,我在桌面应用程序上生成了一个公钥/私钥对,并使用以下代码将它们加载到智能卡上(以
BigInteger类型生成,我将它们转换为十六进制,并从十六进制转换为字节数组):void keyGen(String ID)throws Exception{ // where ID is the name of the user KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair kp = kpg.genKeyPair(); this.pubKey = (RSAPublicKey) kp.getPublic(); this.privKey = (RSAPrivateKey) kp.getPrivate(); KeyFactory fact = KeyFactory.getInstance("RSA"); this.pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class); this.priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class); saveToFile(ID+".pub", pub.getModulus(), pub.getPublicExponent()); saveToFile(ID+".priv", priv.getModulus(), priv.getPrivateExponent()); }
这里是 savetofile 函数:
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException();
} finally {
oout.close();
}
}
这是用于在智能卡上存储公钥的行:
Main.sRmi.setPub(Crypto.hexStringToByteArray(Main.crypto.getPubMod().toString(16)),
toByteArray("0"+Main.crypto.getPubexp().toString(16)));
(在字符串中添加零是因为我们无法将奇数十六进制字符串转换为字节)
-
然后我尝试使用卡内的公钥加密数据,这就是我正在使用的功能:
private Cipher cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); private byte[] cipherText = new byte[64]; public byte[] encrypt(byte[] clearText){ cipherRSA.init(rsa_PublicKey, Cipher.MODE_ENCRYPT); cipherRSA.doFinal(clearText, (short)0, (short)clearText.length,cipherText, (short)0 ); return cipherText; } 然后我尝试在另一个桌面应用程序上获取此加密值,并使用我从文件中读取的私钥对其进行解密:
这是我从文件中读取私钥的方式:
public void init (String ID ) throws FileNotFoundException, IOException, Exception{
Object o[] = openFile(ID+".pub");
setPubMod((BigInteger) o[0]);
setPubexp((BigInteger) o[1]);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(this.pubMod, this.pubexp);
KeyFactory fact = KeyFactory.getInstance("RSA");
pubKey = (RSAPublicKey) fact.generatePublic(keySpec);
o = openFile(ID+".priv");
setPrivMod((BigInteger) o[0]);
setPrivexp((BigInteger) o[1]);
RSAPrivateKeySpec keySpec1 = new RSAPrivateKeySpec(this.privMod, this.privexp);
fact = KeyFactory.getInstance("RSA");
privKey = (RSAPrivateKey) fact.generatePrivate(keySpec1);
cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
}
得到BigInteger变量中的私钥后,我使用如下方法解密:
public byte[] rsaDecrypt(byte[] data) throws Exception, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] clearData = cipher.doFinal(data);
return clearData;
}
总而言之,我以BigInteger 格式创建了一个密钥对,我将BigInteger 变量保存到两个BigInteger 的Serialized 数组中,以供其他桌面应用程序使用,然后我将它们转换为Hexa String,然后放入我放入智能卡中的字节数组。
谁能告诉我这个程序有什么问题?是不是太多了?有更好的方法吗?
我想我知道问题出在哪里,它是存储在智能卡中的密钥,按照我所做的方式转换它显然是行不通的,看看我是如何从卡中读取并打印出来的,得到了完全不同的结果结果,所以现在的问题是,如何将在 java.crypto(BigInteger 中)上创建的公钥成功导出到公钥存储在字节中的智能卡中?
我发现了这个:
设置密钥的公共指数值。明文数据格式是大端和右对齐(最低有效位是最后一个字节的最低有效位)。输入指数数据被复制到内部表示中。
那么如何将大整数转换为这种大端字节格式?
现在我正在尝试设置公钥,这是我正在执行的代码:
public void setPub(byte[] expo,byte[] mod){
rsa_PublicKey.clearKey();
rsa_PublicKey.setExponent(expo, (short)0, (short)expo.length);
rsa_PublicKey.setModulus(mod, (short)0, (short)mod.length);
}
其中 expo 是一个 65 字节数组,mod 是一个由密钥生成器生成的 3 字节数组,但我收到了这个错误:
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: com.sun.javacard.impl.NativeMethods.getCurrentContext()B
at com.sun.javacard.impl.NativeMethods.getCurrentContext(Native Method)
at com.sun.javacard.impl.PrivAccess.getCurrentAppID(PrivAccess.java:454)
at javacard.framework.CardRuntimeException.<init>(CardRuntimeException.java:46)
at javacard.security.CryptoException.<init>(DashoA10*..:25)
at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.throwIt(Unknown Source)
at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.throwException(Unknown Source)
at com.sun.javacard.javax.smartcard.rmiclient.CardObjectFactory.getObject(Unknown Source)
at com.sun.javacard.rmiclientlib.JCRemoteRefImpl.parseAPDU(Unknown Source)
at com.sun.javacard.rmiclientlib.JCRemoteRefImpl.invoke(Unknown Source)
at sid2.CompteurImpl_Stub.setPub(Unknown Source)
at sid2.ServerRmi.setPub(ServerRmi.java:27)
at AddCard$2.actionPerformed(AddCard.java:160)
这就是密钥 priv 和 pub 的生成方式:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair kp = kpg.genKeyPair();
this.pubKey = kp.getPublic();
this.privKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
this.pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
this.priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
【问题讨论】:
-
BigInteger 根据stackoverflow.com/a/5878630/1096742已经是大端格式
-
是的,谢谢,刚刚用谷歌搜索过,但现在我又卡住了。
标签: java encryption rsa public-key-encryption javacard