我经历过很多类似的话题,但是没有运气!
我想使用PEM文件生成公钥和私钥。以下是我用于同一代码:
String pemFileNme = "C:\\Users\\amitmm\\Desktop\\clean\\key.pem";
File pubKeyFile = new File(pemFileNme);
File privKeyFile = new File(pemFileNme);
// read public key DER file
DataInputStream dis = new DataInputStream(new
FileInputStream(pubKeyFile));
byte[] pubKeyBytes = new byte[(int)pubKeyFile.length()];
dis.readFully(pubKeyBytes);
dis.close();
// read private key DER file
dis = new DataInputStream(new FileInputStream(privKeyFile));
byte[] privKeyBytes = new byte[(int)privKeyFile.length()];
dis.read(privKeyBytes);
dis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// decode public key
X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKeyBytes);
RSAPublicKey pubKey = (RSAPublicKey)
keyFactory.generatePublic(pubSpec);
// decode private key
PKCS8EncodedKeySpec privSpec = new
PKCS8EncodedKeySpec(privKeyBytes);
RSAPrivateKey privKey = (RSAPrivateKey)
keyFactory.generatePrivate(privSpec);
例外:
Exception in thread "main" java.security.spec.InvalidKeySpecException:
java.security.InvalidKeyException: invalid key format
at
sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at main.java.me.txedo.security.Main2.f1(Main2.java:47)
at main.java.me.txedo.security.Main2.main(Main2.java:20)
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.x509.X509Key.decode(X509Key.java:387)
PEM文件内容:
----- BEGIN RSA私钥----- MIIEowIBAAKCAQEAwnEEodFEf86 + Ae + wYyI // u1kekIWnA3RfzbAwWD77uG7D9Ci 9vVNbPO4XT2hKL03 / q7d7KTgrA1sjBltfaOzVfA56x1S / 0cYVk4xI440dpLo0F + m RIqRw5fh8IuUlUIr3I4A7ESkDQQsZbDpdggCiNbrlADqLotcZyB4rU4uURW8QUI / W eqsD6TOQs4bI + 3o3xAKkky2kXujSaaa3tDxgUPTmSQ0Buk7Hx / IVzwyV7qjWiR4U C46rHpnWxfF0DWuJUOYgJmBQ8xFOQwt4Ec / u + 0m8top8cqQF + gpBn9iLXpbtahA3 pqyvLuNXRH9yn8mlEneBrjjl6U0H3W / AV7 / dGwIBAwKCAQEAgaCtwTYtqonUAUp1 l2wqqfOYUYFkaAk2VM8rK5X9SevSCosXT04znffQPikWGyjP / x8 + ncNAcrOdsrue U8J3jqAmnL43VNoQOYl2F7Qi + bdF4D / ELbG2gmVBSwe4Y4FykwlV8thtXgLIQ8tG TqsWznyYqtGybI9mhWlyN7Ji2POMDZP5Lwx7M01pMezwpnsZSmPVL9TgVrtWv4xt C0vPyuy9THlFWtkOdHItNK + vOTcpuHn29rFUJI / D3R + SQjcdqj3aaqljOtdeBxgd yDl2 / Z4rUyetgzcZMfNTt / NRT0hOJ6R6 / 2S7gFCTtxMHBh3vVCH + pLLnQyJvcPQu AsORSwKBgQDhOPr1x / 8BioqaasoXvO9NsGktCgPDjbC4d3jR8n6lCa42X / eIahaD xi1VGWyQhdO7aMXiDmzOtox7xHcMRh + a5ySIs9gTsHkMB2hqwIUNg25INRkQ3Vr3 eWnoTBGsfJqC1TEME3ocKwmyz57ZAe4yyR / ZRdDX5DUt9qCCFeA8uQKBgQDdAzbq 7BlJkbTYfdlIRNJEJAO3wWqQTx8X0ttCMMwDluOT9l + RR / KuUxl85ph + kwJci6E / ixfeMTW1NcsMY / lB6mTP0oooalU1MP7gpPSu + 24zhLXnUHZotbNbv9nk6w / 1WWhz FBt5w2DG4kQPFK6LSySqcVuzIGQyvWD5PbpGcwKBgQCWJfyj2qoBBwcRnIa6ffTe dZtzXAKCXnXQT6XhTFRuBnQkP / pa8WRX2XOOEPMLA + J88IPsCZ3fJF2n2E9dhBUR 722wd + VidaYIBPBHKwNeV57azhC16OdPpkaa3WEdqGcB43YIDPwSx1vMimnmAUl3 ML / mLos6mCNz + cBWuUAoewKBgQCTV3nx8ruGYSM6 / pDa2IwtbVfP1kcK32oP4eeB dd1Xue0NTupg2qHJjLuombr / DKw9smt / sg / pdiPOI9yy7VDWnEM1NwbFnDjOIKnr GKMfUkl3rc6aNaRFzneSf + aYnLVOO5r3Yrz715XZ7C1fYx8Hh23G9j0iFZgh05X7 fnwu9wKBgHyC0X26KZQ0ukan5jDSiz4dapUp2d3F + vnRzZa2AOsmo995gsXLdfsJ n0o4Z3LsQJUDRI3tQ4dXe / 5jS4oFrOdxALOAw6YmvEv / 3oHwsCYPDhqLNfIJ9I6m Dt3yG61pUJiCArhPaYG17NQoCxF6Xi6GUajRsECbr8DdyGMAu5eE -----结束RSA私钥-----
我尝试手动删除文件的页眉和页脚。我尝试了来自Bouncycastle的代码,没有运气,同样的错误。
与此文件兼容的Python代码:
def t2e_enc(plaintext, pk_pem_file = './2017-12-04T062008Z.pem'):
'''
Function for encryption of Track2 credit card data.
This function uses private key to derivate public part used for encryption
'''
with open(pk_pem_file, 'rb') as pk:
private_key = serialization.load_pem_private_key(pk.read(),
password=None, backend=default_backend())
public_key = serialization.load_pem_public_key(
private_key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo),
backend=default_backend()
)
ciphertext = public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
b64ciphertext=base64.b64encode(ciphertext)
return b64ciphertext
我第一次这样做,所以如果有任何愚蠢的错误,请多包涵。
答案 0 :(得分:4)
部分欺骗Load RSA public key from file
因此,您“编写”(假定为复制)代码清楚地表明您需要两个DER格式的文件,其中包含PKCS8和“ X509”编码。 (Java在这里所谓的X.509实际上是X.509的SubjectPublicKeyInfo component 。)您给它一个文件,以PEM格式而不是DER,包含一个PKCS1编码,而不是PKCS8 或 X509-您很惊讶它不起作用? Python之所以有效,是因为它调用了OpenSSL,而OpenSSL支持私钥的十几种编码和格式,包括这种编码和格式。 Java仅支持一种(在密钥库之外),而事实并非如此。 (裸)公钥要好一些;内部libcrypto支持多种形式,但实际上仅使用其中两种形式,并且其中一种与Java匹配-尽管许多公共密钥以X.509证书的形式进行分布,存储和使用,这提供了更多的形式供您担心关于。
针对您的情况,大约有7种解决方案:
最简单的方法是使用OpenSSL命令行将您的一个文件转换为Java想要的两个文件:
# (corrected! pkey is inconsistent!)
openssl pkcs8 -topk8 -nocrypt -in input.pem -outform der -out private.der
openssl pkey -in input.pem -pubout -outform der -out public.der
# or for very old versions (should not be needed now)
openssl rsa -in input.pem -pubout -outform der -out public.der
这些文件现在可以通过您发布的代码读取(文件名分开的除外)。注意,该转换不必在同一系统上完成;如有必要,您可以在其他地方进行操作并复制文件(如果使用的方法适用于二进制文件),即不要剪切粘贴。
如果您只想要一个文件,但可以转换,则如上所述创建private.der
文件,并仅使用代码中与私钥相关的部分进行读取,然后执行:
RSAPrivateCrtKey priv2 = (RSAPrivateCrtKey)privKey;
PublicKey pubkey = keyFactory.generatePublic(new RSAPublicKeySpec(priv2.getModulus(), priv2.getPublicExponent()));
您可以通过从上述转换中省略-outform der
来将文件转换为PKCS8和'X509'
结合这些,您可以只转换为PKCS8 PEM,每个项目符号3读取它(去PEM然后是代码的私钥部分),然后从每个项目符号2的私钥中提取公钥
使用纯Java中的格式(未转换)的一种方法是,根据项目符号3取消PEM,为您提供PKCS1编码,然后手动构造PKCS8编码,然后像以前一样继续运行PKCS8,直到完成KeyFactory
并提取每个项目符号的公钥2。请参阅我在Java: Convert DKIM private key from RSA to DER for JavaMail上的答案以获取执行此操作的非常难看的方法(包括一种de-PEM方法)。如果您使用BouncyCastle(具有用于此ASN.1类型的类),则是一种更好的方法,但是,如果您使用BouncyCastle,则最好完全不使用此方法,请参见下文。
在纯Java中使用未转换格式的另一种方法是根据项目符号3解PEM,然后解析the ASN.1 structure of PKCS1并构造一个RSAPrivateCrtKeySpec
,您可以在{{1} } 而不是使用PKCS8编码,然后每个子弹2提取publickey。这甚至更加复杂,尽管我认为我在某处看到过它。如果发现的话会添加。再次,BouncyCastle可以改进此方法,但不需要,请参见下文。
最后,如果您有BouncyCastle,那就太容易了。您没有说“没有运气”时尝试了什么,但是下面的BouncyCastle代码是您所需要的并且可以正常工作:
KeyFactory
请注意,这为您提供了一个文件中包含私钥和公钥对象的try( Reader r = new FileReader(filename) ){
KeyPair pair = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair)new PEMParser(r).readObject());
}
。