C#与Java的RSA中的X509EncodedKeySpec、PKCS8EncodedKeySpec
1、JAVA - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥
private static final String KEY_ALGORITHM = "RSA";
private static final String PUBLIC_KEY ="publicKey";
private static final String PRIVATE_KEY ="privateKey";
public static void main(String[] args) throws Exception{
Map<String,String> keyMap = genKey();
RSAPublicKey publicKey = getPublicKey(keyMap.get(PUBLIC_KEY));
RSAPrivateKey privateKey = getPrivateKey(keyMap.get(PRIVATE_KEY));
String info ="明文123456";
//加密
byte[] bytes = encrypt(info.getBytes("utf-8"),publicKey);
//解密
bytes = decrypt(bytes, privateKey);
System.out.println(new String(bytes,"utf-8"));
}
public static Map<String,String> genKey() throws NoSuchAlgorithmException{
Map<String,String> keyMap = new HashMap<String,String>();
KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
SecureRandom random = new SecureRandom();
// random.setSeed(keyInfo.getBytes());
// 初始加密,512位已被破解,用1024位,最好用2048位
keygen.initialize(1024, random);
// 取得密钥对
KeyPair kp = keygen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey)kp.getPrivate();
String privateKeyString = Base64.encode(privateKey.getEncoded());
RSAPublicKey publicKey = (RSAPublicKey)kp.getPublic();
String publicKeyString = Base64.encode(publicKey.getEncoded());
keyMap.put(PUBLIC_KEY, publicKeyString);
keyMap.put(PRIVATE_KEY, privateKeyString);
return keyMap;
}
public static RSAPublicKey getPublicKey(String publicKey) throws Exception{
byte[] keyBytes = LBase64.decode(publicKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return (RSAPublicKey) keyFactory.generatePublic(spec);
}
public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception{
byte[] keyBytes = LBase64.decode(privateKey);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return (RSAPrivateKey) keyFactory.generatePrivate(spec);
}
2、C# - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥
/*********** Java代码 ***********/
//System.out.println(bytes2hex(publicKey.getModulus().toByteArray()));
//System.out.println(bytes2hex(publicKey.getPublicExponent().toByteArray()));
//设定RSA参数,用于指定modulus和exponent
var parameter = new RSAParameters();
parameter.Modulus = modulusBytes; //modulusBytes是转化后的byte[]
parameter.Exponent = exponentBytes;
//加密
var rsa = RSACryptoServiceProvider.Create("RSA");
rsa.ImportParameters(parameter);
byte[] result = rsa.EncryptValue(Encoding.UTF8.GetBytes("PASSWORD"));
//把密文转化为HEX形式
string resultHex = BitConverter.ToString(result).Replace("-", "");
#if 0
//把3个变量转化为System.Numerics.BigInteger
var modulus = new BigInteger(modulusBytes);
var exponent = new BigInteger(exponentBytes);
var data = new BigInteger(Encoding.UTF8.GetBytes("PASSWORD"));
//做ModPow运算得到密文,也是BigInteger
var result = BigInteger.ModPow(data, exponent, modulus);
//把密文BigInteger对应的byte[]转化为HEX形式
string resultHex = BitConverter.ToString(result.ToByteArray()).Replace("-", "");
#endif
//把3个变量转化为System.Numerics.BigInteger
var modulus = new BigInteger(modulusBytes.Reverse().ToArray());
var exponent = new BigInteger(exponentBytes.Reverse().ToArray());
var data = new BigInteger(Encoding.UTF8.GetBytes("PASSWORD").Reverse().ToArray());
//做ModPow运算得到密文,也是BigInteger
var result = BigInteger.ModPow(d, e, m);
//把密文BigInteger对应的byte[]转化为HEX形式
string resultHex = BitConverter.ToString(result.ToByteArray().Reverse().ToArray()).Replace("-", "");
3、C# - JAVA - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥解析
1. Java程序员很少想过getEncoded()是什么算法,它是如何把modulus与publicExponent封装到一个byte[]里去的。
2. 而对于C#程序员来讲,RSA公钥加密必须要用到modulus与publicExponent,无论它们是XML形式还是byte[]形式,因此如何从publicKeyHex中解析这两个参数就成了第一个关键点。
3. JavaDoc:
An Encoded Form
This is an external encoded form for the key used when a standard representation of the key is needed outside
the Java Virtual Machine, as when transmitting the key to some other party. The key is encoded according to
a standard format (such as X.509 SubjectPublicKeyInfo or PKCS#8), and is returned using the getEncoded method.
Note: The syntax of the ASN.1 type SubjectPublicKeyInfo is defined as follows:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
For more information, see RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile.
根据ASN.1标准进行保存的,涉及到了2种格式:X.509 SubjectPublicKeyInfo和PKCS#8, 具体是哪种可以从getFormat()的方法说明里可以找到答案:公钥使用的是X.509 SubjectPublicKeyInfo,私钥使用的是PKCS#8。
JavaDoc里已经描述了SubjectPublicKeyInfo的结构如下:
SEQUENCE {
SEQUENCE { //algorithm,我们不用关心具体结构
}
BIT STRING { //SubjectPublicKey,以BIT STRING存储
SEQUENCE {
INTEGER //modulus
INTEGER //publicExponent
}
}
}
Java端使用的是2048位的标准RSA加密,给出的公钥HEX字符串如下:
30820122300D06092A864886F70D01010105000382010F003082010A02820101008C214751E6EA33378080F64BF55C0888D3EFA4DF08794318069DDFD14A3AB6468B20CD134819100FA20539785AECF595CF2333F7ADC48366F4ACBC41B1CED728B57417CF3B6CA4E7DDB9DA348F7D38158DD6F2FF3934AEB0A70732E2949505EF893A940404B1B5F4B69243E2877BBA90E5994EBFD61986F412DE4AD3E8331CE1D3D41ADAEF5C79D5B22E05C7F76FC748BC5FA42345D70EC3D1DE3DBD338C300C3750841E2E16E7B907E536FCA1A40D05DC9DFCDE4EB2E8575228309AD146486E6F21C386E90C36DEECB57F955CE68609204AFBD434F8A1BFB5D921C470EED82CCA8BFDA92A8EC668E9E9EB6F959CD535C8BCCFCB08A671983A27E8B03F5BF90D0203010001
对照着ASN.1规范,格式如下:
二进制 解析 -------------------------------------------------------------- 30 0011 0000 TAG:类型00=通用,1=结构体,10000=16=SEQUENCE 82 1000 0010 LEN:定长,长形式,后面2字节是长度 01 长度 0x122=290字节,注意是大字节序 22 30 0011 0000 TAG:类型00=通用,1=结构体,10000=16=SEQUENCE 0D 0000 1101 LEN:定长,短形式,13字节 06 VAL:13字节,我们不关心内容,跳过 09 . . . 05 00 03 0000 0011 TAG:类型00=通用类型,0=简单数据,00011=3=BIT STRING 82 1000 0010 LEN:定长,长形式,后面2字节是长度,注意是大字节序 01 长度 0x10f=271字节 0F 00 保留字 30 0011 0000 TAG:类型00=通用类型,1=结构体,10000=16=SEQUENCE 82 1000 0010 LEN:定长,长形式,后面2字节是长度,注意是大字节序 01 长度 0x10a=266字节 0A 02 0000 0010 TAG:类型00,0=简单数据,00010=2=INTEGER 82 1000 0010 LEN:定长,长形式,后面2字节是长度,注意是大字节序 01 长度=0x101,257字节 01 00 VAL:257字节,是公钥中的modulus 8C . . . F9 0D 02 0000 0010 TAG:类型00,0=简单数据,00010=2=INTEGER 03 0000 0011 LEN:定长,短形式,3字节 01 00 01 VAL:3字节,是公钥中的publicExponent

浙公网安备 33010602011771号