Original article. For more information, see http://boytnt.blog.51cto.com/966121/1350441.
Some time ago, a project involved calling the interface of the external Java System in the C # project. The login function requires the C # End to negotiate the RSA public key with the Java end first, then, use the public key to encrypt the password and submit it to the Java end for verification. Java uses 2048-bit standard RSA encryption, and the Public Key is a HEX string, such:
Bytes Bytes Bytes Bytes Bytes 983A27E8B03F5BF90D0203010001
|
The algorithm of RSA itself is not complex. I believe many people have performed encryption and decryption in projects, and different languages are well encapsulated. However, the problem arises when the algorithm is cross-language. I have studied this project in depth.
First, let's see how this public key comes from. In Java, a key pair is generated and the output Public Key is encoded as follows:
/************ Java code *********** // initialize the 2048-bit RSA key generator KeyPairGenerator generator = KeyPairGenerator. getInstance ("RSA"); generator. initialize (2048); // generate a key pair and obtain the public key and private key KeyPair keys = generator. generateKeyPair (); RSAPublicKey publicKey = (RSAPublicKey) keys. getPublic (); rsw.vatekey privateKey = (rsw.vatekey) keys. getPrivate (); // encoded and converted into a HEX String publicKeyHex = bytes2hex (publicKey. getEncoded (); System. out. println (publicKeyHex );
The large string starting with 3082 in the beginning of this article is produced in this way. This is generally done in Java when public key encryption is required:
/************ Java code *********** // restore the public key KeyFactory factory = KeyFactory. getInstance ("RSA"); X509EncodedKeySpec spec = new X509EncodedKeySpec (hex2byte (publicKeyHex); PublicKey publicKey = factory. generatePublic (spec); // RSA public key encryption (non-fill mode) Cipher cipher = Cipher. getInstance ("RSA/ECB/NoPadding"); cipher. init (Cipher. ENCRYPT_MODE, publicKey); byte [] result = cipher. doFinal ("PASSWORD ". getBytes ("UTF-8"); // converts ciphertext to HEX String resultHex = byte2hex (result );
The above two pieces of code involve the conversion between byte [] and HEX strings. Let's also take a look:
/************ Java code ***********/private byte [] hex2bytes (String hex) {String numeric = "0123456789 ABCDEF"; char [] hex2char = hex. toCharArray (); byte [] bytes = new byte [hex. length ()/2]; int temp; for (int I = 0; I <bytes. length; I ++) {temp = digital. indexOf (hex2char [2 * I]) * 16; temp + = digital. indexOf (hex2char [2 * I + 1]); bytes [I] = (byte) (temp & 0xff);} return bytes;} private String bytes2hex (byte [] B) {String hs = ""; String stmp = ""; for (int n = 0; n <B. length; n ++) {stmp = (java. lang. integer. toHexString (B [n] & 0xFF); if (stmp. length () = 1) hs = hs + "0" + stmp; else hs = hs + stmp;} return hs. toUpperCase ();}
I believe that the vast majority of Java programmers have never thought about what the getEncoded () algorithm is and how it encapsulates modulus and publicExponent into a byte. For C # programmers, the RSA public key encryption must use modulus and publicExponent, whether in XML or byte [] format, therefore, how to resolve the two parameters from publicKeyHex becomes the first key point.
Let's take a look at what JavaDoc says.
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 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. |
According to the ASN.1 standard, two formats are involved: X.509 SubjectPublicKeyInfo and PKCS #8. Which of the following formats can be found in the getFormat () method description: the public key uses X.509 SubjectPublicKeyInfo and the private key uses PKCS #8.
We only care about the public key. OK. Next, let's take a look at how to solve the modulus and publicExponent we need. Unfortunately, there are no ready-made classes in. NetFramework to process ASN.1 and SubjectPublicKeyInfo. There are several ways to get data:
1. Use Win32API to introduce the unmanaged code crypt32.dll and call the CryptDecodeObject () method to decode it.
2, the use of third-party class libraries, such as BouncyCastle, it has C # implementation, http://www.bouncycastle.org/csharp
3. Self-Analysis
I personally recommend BouncyCastle, but this article intends to "go deeper", so we are going to take 3rd steps.
To be continued ......
This article from the rabbit nest blog, please be sure to keep this source http://boytnt.blog.51cto.com/966121/1350441