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
