Implementation of asymmetric encryption and digital signature RSA Algorithms (public key encryption-> Private Key decryption, private key encryption-> Public Key decryption)

Source: Internet
Author: User
Tags modulus asymmetric encryption

The RSA algorithm is the first algorithm that can be used for both data encryption and digital signature. It is easy to understand and operate, and is also popular. Its security is based on the difficulty of big integer factorization, while the big integer factorization is a famous mathematical problem. So far, there is no effective solution, therefore, the security of the RSA algorithm can be ensured.

The RSA algorithm consists of the generation of public and private keys, asymmetric encryption and decryption, digital signature and verification, next we will introduce the working principle of the RSA algorithm and my implementation methods one by one.

1. Generation of public and private keys

Select two prime numbers p and q at will. p is not equal to q and n = p * q is calculated.
Select an integer e randomly to satisfy the requirements of e and (p-1) * (q-1. (Note: e is easy to choose, such as 3, 17,655 37 .. In NET Framework, e is 65537 by default)
The Euclid algorithm is used to calculate and decrypt the key d.
E * d limit 1 (mod (p-1) * (q-1 ))
N and d must also be mutually dependent.

E and n are public keys, and d and n are private keys. P and q are destroyed.

 

In the. NET Framework RSA algorithm, e corresponds to RSAParameters. Exponent; d corresponds to RSAParameters. D; n corresponds to RSAParameters. ModulusExponent .. By default, the RSA Algorithm in the. NET Framework uses a 1024-bit key. The public key and private key are implemented by using RSACryptoServiceProvider of. NET Framework to generate the Public Key xml file and private key xml file. The program that generates the xml file of the public key and private key.

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (); </p> <p> // generate a public key XML string <br/> string publicKeyXmlString = rsa. toXmlString (false); </p> <p> // generate the private key XML string <br/> string privateKeyXmlString = rsa. toXmlString (true );

The public key and private key are imported from the generated public key xml file and private key xml file.

Public class RSAPublicKey <br/>{< br/> public byte [] Modulus; <br/> public byte [] Exponent; </p> <p> public static RSAPublicKey FromXmlString (string xmlString) <br/>{< br/> if (string. isNullOrEmpty (xmlString) <br/>{< br/> return null; <br/>}</p> <p> try <br/> {<br/> using (XmlReader reader = XmlReader. create (new StringReader (xmlString) <br/>{< br/> if (! Reader. ReadToFollowing ("RSAKeyValue") <br/>{< br/> return null; <br/>}</p> <p> if (reader. LocalName! = "Modulus "&&! Reader. readToFollowing ("Modulus") <br/>{< br/> return null; <br/>}< br/> string modulus = reader. readElementContentAsString (); </p> <p> if (reader. localName! = "Exponent "&&! Reader. readToFollowing ("Exponent") <br/>{< br/> return null; <br/>}< br/> string exponent = reader. readElementContentAsString (); </p> <p> RSAPublicKey publicKey = new RSAPublicKey (); <br/> publicKey. modulus = Convert. fromBase64String (modulus); <br/> publicKey. exponent = Convert. fromBase64String (exponent); </p> <p> return publicKey; <br/>}< br/> catch <br/> {<br/> return null; <br/>}< br/>}
Public class RSAPrivateKey <br/>{< br/> public byte [] Modulus; <br/> public byte [] D; </p> <p> public static rsw.vatekey FromXmlString (string xmlString) <br/>{< br/> if (string. isNullOrEmpty (xmlString) <br/>{< br/> return null; <br/>}</p> <p> try <br/> {<br/> using (XmlReader reader = XmlReader. create (new StringReader (xmlString) <br/>{< br/> if (! Reader. ReadToFollowing ("RSAKeyValue") <br/>{< br/> return null; <br/>}</p> <p> if (reader. LocalName! = "Modulus "&&! Reader. readToFollowing ("Modulus") <br/>{< br/> return null; <br/>}< br/> string modulus = reader. readElementContentAsString (); </p> <p> if (reader. localName! = "D "&&! Reader. readToFollowing ("D") <br/>{< br/> return null; <br/>}< br/> string d = reader. readElementContentAsString (); </p> <p> rs?vatekey privateKey = new rs?vatekey (); <br/> privateKey. modulus = Convert. fromBase64String (modulus); <br/> privateKey. D = Convert. fromBase64String (d); </p> <p> return privateKey; <br/>}< br/> catch <br/> {<br/> return null; <br/>}< br/>}
2. asymmetric encryption and decryption
When the private key is encrypted in m (binary representation), the data block m1, m2... mi of m is first divided into s, where 2 ^ s <= n, s is as big as possible. Perform the following calculation:
Ci = mi ^ d (mod n)
When the public key decrypts c (binary representation), you also need to split the data block c1, c2... ci in the c-point growth s and perform the following calculation:
Mi = ci ^ e (mod n)

In some cases, public key encryption is also used-> Private Key decryption. The principle is the same as private key encryption-> Public Key decryption. The following are private key calculation and public key calculation algorithms. The BigInteger class of Chew Keong TAN is used .. The BigInteger. ModPow method provided in NET Framework 4 seems to be faulty.

Private static byte [] Compute (byte [] data, RSAPublicKey publicKey, int blockSize) <br/> {<br/> // public key encryption/Decryption formula: ci = mi ^ e (mod n) <br/> // first, divide m (binary representation) into data blocks m1, m2 ,..., mi. <Br/> // <br/> BigInteger e = new BigInteger (publicKey. exponent); <br/> BigInteger n = new BigInteger (publicKey. modulus); </p> <p> int blockOffset = 0; <br/> using (MemoryStream stream = new MemoryStream ()) <br/>{< br/> while (blockOffset <data. length) <br/> {<br/> int blockLen = Math. min (blockSize, data. length-blockOffset); <br/> byte [] blockData = new byte [blockLen]; <br/> Buffer. blockCopy (da Ta, blockOffset, blockData, 0, blockLen); </p> <p> BigInteger mi = new BigInteger (blockData); <br/> BigInteger ci = mi. modPow (e, n); // ci = mi ^ e (mod n) </p> <p> byte [] block = ci. getBytes (); <br/> stream. write (block, 0, block. length); <br/> blockOffset + = blockLen; <br/>}</p> <p> return stream. toArray (); <br/>}</p> <p> private static byte [] Compute (byte [] data, rsw.vatekey privateKey, int BlockSize) <br/>{< br/> // <br/> // Private Key Encryption/Decryption formula: mi = ci ^ d (mod n) <br/> // divide c (binary representation) into data blocks c1, c2 ,..., and then perform operations. <Br/> // <br/> BigInteger d = new BigInteger (privateKey. d); <br/> BigInteger n = new BigInteger (privateKey. modulus); </p> <p> int blockOffset = 0; </p> <p> using (MemoryStream stream = new MemoryStream ()) <br/>{< br/> while (blockOffset <data. length) <br/> {<br/> int blockLen = Math. min (blockSize, data. length-blockOffset); <br/> byte [] blockData = new byte [blockLen]; <br/> Buffer. blockCopy (data, blockOffset, blockData, 0, blockLen); </p> <p> BigInteger ci = new BigInteger (blockData); <br/> BigInteger mi = ci. modPow (d, n); // mi = ci ^ d (mod n) </p> <p> byte [] block = mi. getBytes (); <br/> stream. write (block, 0, block. length); <br/> blockOffset + = blockLen; <br/>}</p> <p> return stream. toArray (); <br/>}< br/>}
The implementation of private key encryption> Public Key decryption is as follows:

Public static byte [] Encrypt (byte [] data, RSAPublicKey publicKey) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data"); <br/>}</p> <p> if (publicKey = null) <br/>{< br/> throw new ArgumentNullException ("publicKey"); <br/>}</p> <p> int blockSize = publicKey. modulus. length-1; <br/> return Compute (data, publicKey, blockSize ); <br/>}</p> <p> public static byte [] Decrypt (byte [] data, rsw.vatekey privateKey) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data "); <br/>}</p> <p> if (privateKey = null) <br/>{< br/> throw new ArgumentNullException ("privateKey "); <br/>}</p> <p> int blockSize = privateKey. modulus. length; <br/> return Compute (data, privateKey, blockSize); <br/>}
The implementation of public key encryption> Private Key decryption is as follows:

Public static byte [] Encrypt (byte [] data, rsw.vatekey privateKey) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data"); <br/>}</p> <p> if (privateKey = null) <br/>{< br/> throw new ArgumentNullException ("privateKey"); <br/>}</p> <p> int blockSize = privateKey. modulus. length-1; <br/> return Compute (data, privateKey, blockSize ); <br/>}</p> <p> public static byte [] Decrypt (byte [] data, RSAPublicKey publicKey) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data "); <br/>}</p> <p> if (publicKey = null) <br/>{< br/> throw new ArgumentNullException ("publicKey "); <br/>}</p> <p> int blockSize = publicKey. modulus. length; <br/> return Compute (data, publicKey, blockSize); <br/>}
3. Digital Signature and Verification
When the private key is used to sign data m, hash m is first calculated to obtain the calculation result h. Then encrypt h with the private key. The encrypted ciphertext s is the signature.
When the public key verifies the signature s, m is first hash calculated to obtain the calculation result h. Then use the public key to decrypt s to get the result H '. If h = h ', the verification is successful. Otherwise, the verification fails.

In some cases, public key signature-> private key verification is also used. The principle is the same as that of Private Key signature-> Public Key verification.

The following describes the implementation of Private Key signature> Public Key verification.

Public static byte [] Sign (byte [] data, RSAPublicKey publicKey, HashAlgorithm hash) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data"); <br/>}</p> <p> if (publicKey = null) <br/>{< br/> throw new ArgumentNullException ("publicKey"); <br/>}</p> <p> if (hash = null) <br/>{< br/> throw new ArgumentNullException ("hash"); <br/>}</p> <p> byte [] hashData = hash. compute Hash (data); <br/> byte [] signature = Encrypt (hashData, publicKey); <br/> return signature; <br/>}</p> <p> public static bool Verify (byte [] data, RSAPrivateKey privateKey, HashAlgorithm hash, byte [] signature) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data "); <br/>}</p> <p> if (privateKey = null) <br/>{< br/> throw new ArgumentNullException ("privateKey"); <br/ >}</P> <p> if (hash = null) <br/> {<br/> throw new ArgumentNullException ("hash "); <br/>}</p> <p> if (signature = null) <br/>{< br/> throw new ArgumentNullException ("signature "); <br/>}</p> <p> byte [] hashData = hash. computeHash (data); <br/> byte [] signatureHashData = Decrypt (signature, privateKey); </p> <p> if (signatureHashData! = Null & signatureHashData. length = hashData. length) <br/> {<br/> for (int I = 0; I <signatureHashData. length; I ++) <br/>{< br/> if (signatureHashData [I]! = HashData [I]) <br/>{< br/> return false; <br/>}< br/> return true; <br/>}</p> <p> return false; <br/>}
The following is the implementation of Public Key signature> private key verification:

Public static byte [] Sign (byte [] data, rsw.vatekey privateKey, HashAlgorithm hash) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data"); <br/>}</p> <p> if (privateKey = null) <br/>{< br/> throw new ArgumentNullException ("privateKey"); <br/>}</p> <p> if (hash = null) <br/>{< br/> throw new ArgumentNullException ("hash"); <br/>}</p> <p> byte [] hashData = hash. com PuteHash (data); <br/> byte [] signature = Encrypt (hashData, privateKey); <br/> return signature; <br/>}</p> <p> public static bool Verify (byte [] data, RSAPublicKey publicKey, HashAlgorithm hash, byte [] signature) <br/>{< br/> if (data = null) <br/>{< br/> throw new ArgumentNullException ("data "); <br/>}</p> <p> if (publicKey = null) <br/>{< br/> throw new ArgumentNullException ("publicKey"); <br />}</P> <p> if (hash = null) <br/>{< br/> throw new ArgumentNullException ("hash "); <br/>}</p> <p> if (signature = null) <br/>{< br/> throw new ArgumentNullException ("signature "); <br/>}</p> <p> byte [] hashData = hash. computeHash (data); </p> <p> byte [] signatureHashData = Decrypt (signature, publicKey); </p> <p> if (signatureHashData! = Null & signatureHashData. length = hashData. length) <br/> {<br/> for (int I = 0; I <signatureHashData. length; I ++) <br/>{< br/> if (signatureHashData [I]! = HashData [I]) <br/>{< br/> return false; <br/>}< br/> return true; <br/>}</p> <p> return false; <br/>}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.