加密从一个文件字符串创建java私钥和公钥
你好
还有另一个第三方需要我的web应用程序以加密格式向他们发送一些数据。所以他们给我发了一些指南,但是,我不熟悉,我试图用谷歌搜索,但看起来我用谷歌搜索错了方向
指南内容如下:
运行openssl命令以生成私钥:
openssl ecparam-name prime256v1-genkey-out myprivate。pem
在运行这个命令之后,我输出了一个priv.pem文件,我看到里面有一个带有“==”的key end,如下所示:
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILefWfeuZOgnbDlxpwo3uQ2xQXfhXHUPTS+vKzvVZdCToAoGCCqGSM49
AwEHoUQDQgAE4MeQspGRJ1qdpweBfiaT5P84alZdga1f7mSpa5HqXTH58u0ZWJUQ
J7ToU/bUOPITh4FX07AV6wrgFCmwtUenDQ==
-----END EC PRIVATE KEY-----
第二个是运行openssl命令生成公钥,然后发送它们:
openssl ec-在myprivate中。pem-pubout-OutMyPublic。pem
将私钥转换为pkcs8格式:
myprivate中的opensslpkcs8-topk8-nocrypt-。pem-out mypkcs8。pem
第三方会给我一个字符串格式的公钥,然后让我生成一个密钥,并提供一些java代码,如下所示:
第一个是生成密钥,第二个是加密:
public static SecretKey generateSharedSecret(PrivateKey privateKey,
PublicKey publicKey) {
try {
KeyAgreement keyAgreement = KeyAgreement.getInstance( "ECDH" );
keyAgreement.init( privateKey );
keyAgreement.doPhase( publicKey, true );
SecretKeySpec key = new SecretKeySpec(
keyAgreement.generateSecret( ), "AES" );
return key;
} catch ( Exception e ) {
// TODO Auto-generated catch block
e.printStackTrace( );
return null;
}
}
public static String encryptString(SecretKey key, String plainText) {
try {
String myIv = "Testing @ IV!";
byte[] iv = myIv.getBytes( "UTF-8" );
IvParameterSpec ivSpec = new IvParameterSpec( iv );
Cipher cipher = Cipher.getInstance( "AES / CBC / PKCS5Padding" );
byte[] plainTextBytes = plainText.getBytes( "UTF-8" );
byte[] cipherText;
cipher.init( Cipher.ENCRYPT_MODE, key, ivSpec );
cipherText = new byte[cipher.getOutputSize( plainTextBytes.length )];
int encryptLength = cipher.update( plainTextBytes, 0,
plainTextBytes.length, cipherText, 0 );
encryptLength += cipher.doFinal( cipherText, encryptLength );
return bytesToHex( cipherText );
} catch ( Exception e ) {
e.printStackTrace( );
return null;
}
}
以及字节到十六进制字符串的方法:
public static String bytesToHex(byte[] byteArray) {
StringBuffer hexStringBuffer = new StringBuffer( );
for ( int i = 0; i < byteArray.length; i++ ) {
hexStringBuffer.append( String.format( "%02X", byteArray[ i ] ) );
}
return hexStringBuffer.toString( );
}
通过使用openssl命令,我有一个私钥和一个公钥,但第四步告诉我,他们也会给我一个公钥,因此我不知道应该使用哪个公钥
还有,如何将字符串转换为javaPrivateKey
和PublicKey
对象
*附加组件* 我尝试将der文件转换为java PublicKey对象,它看起来很有效。在此之前,我使用openssl命令将pem转换为der:
openssl pkey -pubin -in ecpubkey.pem -outform der -out ecpubkey.der
以下是java代码:
File f = new File("/home/my/Desktop/key/ecpubkey.der");
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
KeyFactory fact = KeyFactory.getInstance("EC");
PublicKey theirpub = fact.generatePublic(new X509EncodedKeySpec(keyBytes));
但是,当我尝试将der文件转换为java PrivateKey对象时,我遇到了java.security.spec.InvalidKeySpecException: java.io.IOException: insufficient data
,我所做的是:
openssl ecparam -name prime256v1 -genkey -out priv.pem
openssl pkcs8 -topk8 -nocrypt -in priv.pem -outform der -out priv.der
下面是我的java代码:
File f2 = new File("/home/my/Desktop/key/priv.der");
FileInputStream fis2 = new FileInputStream(f2);
DataInputStream dis2 = new DataInputStream(fis2);
byte[] keyBytes2 = new byte[(int) f.length()];
dis2.readFully(keyBytes2);
dis2.close();
KeyFactory fact2 = KeyFactory.getInstance("EC");
PrivateKey pKey = fact2.generatePrivate( new PKCS8EncodedKeySpec(keyBytes2) ); // this line hit insufficient data
# 1 楼答案
Diffie Hellman在wikipedia中得到了很好的解释,这里可能有数百个Q和crypto中的一些。SX和安全。SX,关于它,但我不容易找到。简而言之:
生成密钥对,保留私钥,并将公钥提供给另一方
另一方做同样的事情(或其反映):生成一个密钥对,保留他们的私钥,并向您提供他们的公钥
您可以使用私钥和他们的公钥来计算“协议”值
他们同样使用私钥和你的公钥来计算相同的“协议”值。这也被称为共享秘密,因为你和另一方都知道,但任何偷听你流量的人都不知道
该概要中的“提供”省略了许多非常重要的细节。重要的是,当你向另一方提供公钥时,他们实际上得到了你的公钥,而不是被对手更改或替换的值,同样,当他们向你提供公钥时,你得到的是真实的公钥,而不是经过修改或伪造的公钥。这是实际的DH系统主要发生故障的地方,而您在这里提到的任何保护措施或复杂性都表明,如果用于任何值得窃取的东西,您的方案将是不安全的,很容易被破坏
注意:你不应该向任何人透露或“发送”你的私钥,他们也不应该同样地透露他们的私钥。这是公钥(或“非对称”)加密具有任何价值或用途的主要基础
有很多方法可以表示密钥,但只有一些与您相关
Public键通常以
ASN。1结构主题PublicKeyInfo在X.509中定义,在PKIX中更方便,主要在rfc5280 #4.1和#4.1.2.7和rfc3279 2.3中定义,在DER中编码,,它的局限性是,这种编码中使用的许多字节都不是有效字符,无法正确显示或以其他方式操作,有时甚至无法传输或存储或
这和ASN一样。1 DER结构以“PEM”格式“包装”,将麻烦的二进制数据转换为易于操作的所有可显示字符。PEM格式最初是为一个安全的电子邮件方案调用Privacy Enhanced Mail创建的,它已被其他方案和技术取代,但它定义的格式仍在使用。最近,{a6}重新标准化了公钥PEM格式(如您所见,参考rfc5280)
OpenSSL支持这两种方式,但您使用的命令行实用程序大多默认为PEM,因为您需要将密钥传递给“他们”,他们也需要将密钥传递给您,所以PEM可能是最可靠和/或方便的方式。(虽然其他格式也是可能的,但如果你和他们同意,并且如果他们要求其他内容,那么你必须同意该方案才能起作用。)
Java直接只支持DER,因此假设您在SPKI PEM中收到他们的公钥,要在Java中使用它,您需要将其转换为DER。您可以在OpenSSL中执行此操作
然后将DER读入Java加密密钥工厂:
或者,您可以让Java转换PEM,这并不太难;有几种变体,但我喜欢:
对于私人密钥 有更多的表示形式,但只有一种(或两种)是Java与OpenSSL共享的。由于您只需要在本地存储私钥,而不需要“发送”,因此可能不需要PEM;如果是这样,您只需将
-outform der
添加到pkcs8 -topk8 -nocrypt
命令中,适当地调整名称,并以与上面相同的方式直接在Java KeyFactory中读取结果,除了使用PKCS8EncodedKeySpec
和generatePrivate
和[EC]PrivateKey
。如果您确实想将其存储在(PKCS8 clear)PEM中,也可以将以上内容结合使用直接使用DH协议值作为对称密码(例如AES)密钥是不标准的,通常不被认为是良好的做法,尽管对于带有prime256v1(又名secp256r1或p-256)的ECDH,在技术上是可能的。AFAIK所有好的标准都在两者之间使用密钥派生步骤(又称密钥派生函数或KDF)。由于您还没有向我们展示他们的“指南”,我不能说这至少对正确的小值是正确的
当然你知道,对于同一个密钥(在本例中是相同的DH结果)多次使用带有固定IV的CBC,是不安全的。我认为“测试”意味着你计划用更好的东西来取代它
另外,仅供参考,您不需要使用
Cipher.init,update,doFinal
API的全部复杂性。当数据足够小,可以放入内存时,如这里所示,您可以执行以下操作:最后,因为Java
byte
是有符号的,所以bytesToHex
将输出几乎一半的前缀为FFFFFF
的字节。这是非常不寻常的,非常丑陋,但我也不知道这对你来说是否“正确”# 2 楼答案
基于dave_thompson_085的解释和代码,我通过以下方式创建了我的java公钥和私钥:
这是私钥
非常感谢@dave_thompson_085的解释