简体   繁体   中英

RSA encryption in C# is different from other language

I am trying to encrypting data in C#

In other language, every encrypted data ended in "==" but in C#, they don't

why this happen?

in python

import base64
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA

def encrpt(password, public_key):
    rsakey = RSA.importKey(public_key)
    cipher = Cipher_pksc1_v1_5.new(rsakey)
    cipher_text = base64.b64encode(cipher.encrypt(password.encode("utf-8")))
    return cipher_text.decode()

public_key = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA81dCnCKt0NVH7j5Oh2+S
GgEU0aqi5u6sYXemouJWXOlZO3jqDsHYM1qfEjVvCOmeoMNFXYSXdNhflU7mjWP8
jWUmkYIQ8o3FGqMzsMTNxr+bAp0cULWu9eYmycjJwWIxxB7vUwvpEUNicgW7v5nC
wmF5HS33Hmn7yDzcfjfBs99K5xJEppHG0qc+q3YXxxPpwZNIRFn0Wtxt0Muh1U8a
vvWyw03uQ/wMBnzhwUC8T4G5NclLEWzOQExbQ4oDlZBv8BM/WxxuOyu0I8bDUDdu
tJOfREYRZBlazFHvRKNNQQD2qDfjRz484uFs7b5nykjaMB9k/EJAuHjJzGs9MMMW
tQIDAQAB
-----END PUBLIC KEY-----
'''

print(encrpt("abc", public_key))

result

jA14duvhdPVipkWYJrvRXuNpD6yNXRwb/VnyEmc8G1UFxQoxhm8j0nPNZFuQ48oB8jZmd0kGBfwwQluPtYrJCqbtZ9qamnNp+xtSHE5BUsbXtfuF55ppWGmPsQkEUADNodMidHeUgGuP4g3E25/Vumx6iN0vRNZNFw3WFOPwAZVQEmNGfN3J2Xa3BSuaVyDh4mLp/SD5wK6ffv5+aSXP3HZQPWVe/YW3+Ok6+O3adVJ4T6r2NNIwabR+aQDqH2rCAePIum8qm8ZcV93jX0y+8pvfHzaSMzNH1dpTjPR47rUatlx44jG2ORKnvfRkACcCS+HhHfQ87WCYxCVUhWuflQ==

in JavaScript

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js"
    crossorigin="anonymous"></script>
  <script>
    const crypt = new JSEncrypt();
    crypt.setPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA81dCnCKt0NVH7j5Oh2+SGgEU0aqi5u6sYXemouJWXOlZO3jqDsHYM1qfEjVvCOmeoMNFXYSXdNhflU7mjWP8jWUmkYIQ8o3FGqMzsMTNxr+bAp0cULWu9eYmycjJwWIxxB7vUwvpEUNicgW7v5nCwmF5HS33Hmn7yDzcfjfBs99K5xJEppHG0qc+q3YXxxPpwZNIRFn0Wtxt0Muh1U8avvWyw03uQ/wMBnzhwUC8T4G5NclLEWzOQExbQ4oDlZBv8BM/WxxuOyu0I8bDUDdutJOfREYRZBlazFHvRKNNQQD2qDfjRz484uFs7b5nykjaMB9k/EJAuHjJzGs9MMMWtQIDAQAB");
    const encrypted = crypt.encrypt("abc").trim();

    document.write(encrypted);
  </script>
</head>
</html>

result

a6zdvw+y8wfQUns1UbwWPXBuChZK9mDx6x8fuX+AFcZC/HwOhU9YIl4vnSlrU5l4Kh7IUMP4LOx5o3Y4n39vXxj4oAEE1ab35y2elp1bYjQUZfXgULRAcx3O2iBSP7Dqht43HKPImagtE/aopuOuK6mwl2a1aeR7J0FCEpF2TXM2Xc+4obq0xXw+fapiGv1qGher0RbyKFNALnUeAfRtfWpYjTJ2XUlWRyE5jU455xmMl5QYFNiJa9R7GynZbolNEf9FIHBrMyuMXNB1OOAyPc6jbeSb2/IckoNR4YNS3IdQY+SE++cm9AvEqfI6e/wCWfJ2pkDN0x3kn+FDb0la5w==

in C#

public static void Main()
        {
            RSACryptoServiceProvider cipher = new RSACryptoServiceProvider();
            cipher.FromXmlString("<RSAKeyValue><Modulus>MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA81dCnCKt0NVH7j5Oh2+SGgEU0aqi5u6sYXemouJWXOlZO3jqDsHYM1qfEjVvCOmeoMNFXYSXdNhflU7mjWP8jWUmkYIQ8o3FGqMzsMTNxr+bAp0cULWu9eYmycjJwWIxxB7vUwvpEUNicgW7v5nCwmF5HS33Hmn7yDzcfjfBs99K5xJEppHG0qc+q3YXxxPpwZNIRFn0Wtxt0Muh1U8avvWyw03uQ/wMBnzhwUC8T4G5NclLEWzOQExbQ4oDlZBv8BM/WxxuOyu0I8bDUDdutJOfREYRZBlazFHvRKNNQQD2qDfjRz484uFs7b5nykjaMB9k/EJAuHjJzGs9MMMWtQIDAQAB</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>");
            byte[] data = Encoding.UTF8.GetBytes("abc");
            byte[] cipherText = cipher.Encrypt(data, true);
            var result = Convert.ToBase64String(cipherText);
            Console.WriteLine(result);
        }

result

IK47Ed8Yw8uAECMFgTMX7Ij7rAqj149QyO2AJ9P4YMzqu2MSAmRcSCKWaPzF9k8OXQmV/aXACjwJMBq2ikZjfBwuoax1rdiIdXFmvUSIbrTDAx83feTDRF+1wO31MROSXi99+LErMMMRPXacqYqcB1fy7b/NhbEdmNLHWCV62B1BvO+DCoDXHM+3ImkhbCTGU2Jeq1EkfCbJSL42RryJv6sKefmwjAcyEdXl/mSHUVdgOJrSbsCsNbkvy/iKq6ZcQnoSkxmlmF/VfFu0Ivj+31fcjY0OGkzD9CkCZGmxsRF1kG0F+lNbwbRPEU5q8pXPqCcas55BMKHJGt2EuK/662qqGr6iiSv1+YxOQ1aofV7dfoNe3sOTekpj3cVM5ART4uwOKNee

only in c# does not have "==" in end. I tried many times and every cases were like this

I think I have big misunderstanding about rsa encrytion but I don't know what I misunderstand. plz help me

The ciphertext of all three codes is Base64 encoded. Base64 uses a padding ( = ). Whether or not padding is applied depends on the length of the data. The C# code generates an incorrect ciphertext due to a bug in the key import (see below). As a result, the ciphertext has a different length than the ciphertexts of the other two codes, which is the reason for the different padding.


In the Python and JavaScript code, the public key is imported as PEM encoded X.509/SPKI key. In the C# code, it is imported as XML, using the body of the PEM encoded key instead of the modulus, which is incorrect.

To fix the issue, the modulus must be extracted from the PEM key. For this purpose, the PEM key can be loaded with a PEM parser, eg lapo.it/asn1js , and the modulus can be determined:

f357429c22add0d547ee3e4e876f921a0114d1aaa2e6eeac6177a6a2e2565ce9593b78ea0ec1d8335a9f12356f08e99ea0c3455d849774d85f954ee68d63fc8d6526918210f28dc51aa333b0c4cdc6bf9b029d1c50b5aef5e626c9c8c9c16231c41eef530be91143627205bbbf99c2c261791d2df71e69fbc83cdc7e37c1b3df4ae71244a691c6d2a73eab7617c713e9c193484459f45adc6dd0cba1d54f1abef5b2c34dee43fc0c067ce1c140bc4f81b935c94b116cce404c5b438a0395906ff0133f5b1c6e3b2bb423c6c350376eb4939f44461164195acc51ef44a34d4100f6a837e3473e3ce2e16cedbe67ca48da301f64fc4240b878c9cc6b3d30c316b5

In XML format the modulus is expected Base64 encoded, which is feasible eg online with cryptii.com/pipes/base64-to-hex :

81dCnCKt0NVH7j5Oh2+SGgEU0aqi5u6sYXemouJWXOlZO3jqDsHYM1qfEjVvCOmeoMNFXYSXdNhflU7mjWP8jWUmkYIQ8o3FGqMzsMTNxr+bAp0cULWu9eYmycjJwWIxxB7vUwvpEUNicgW7v5nCwmF5HS33Hmn7yDzcfjfBs99K5xJEppHG0qc+q3YXxxPpwZNIRFn0Wtxt0Muh1U8avvWyw03uQ/wMBnzhwUC8T4G5NclLEWzOQExbQ4oDlZBv8BM/WxxuOyu0I8bDUDdutJOfREYRZBlazFHvRKNNQQD2qDfjRz484uFs7b5nykjaMB9k/EJAuHjJzGs9MMMWtQ==

Alternatively, an online converter can be used to convert the PEM key directly into the XML format, eg superdry.apphb.com/tools/online-rsa-key-converter :

<RSAKeyValue>
    <Modulus>81dCnCKt0NVH7j5Oh2+SGgEU0aqi5u6sYXemouJWXOlZO3jqDsHYM1qfEjVvCOmeoMNFXYSXdNhflU7mjWP8jWUmkYIQ8o3FGqMzsMTNxr+bAp0cULWu9eYmycjJwWIxxB7vUwvpEUNicgW7v5nCwmF5HS33Hmn7yDzcfjfBs99K5xJEppHG0qc+q3YXxxPpwZNIRFn0Wtxt0Muh1U8avvWyw03uQ/wMBnzhwUC8T4G5NclLEWzOQExbQ4oDlZBv8BM/WxxuOyu0I8bDUDdutJOfREYRZBlazFHvRKNNQQD2qDfjRz484uFs7b5nykjaMB9k/EJAuHjJzGs9MMMWtQ==</Modulus>
    <Exponent>AQAB</Exponent>
</RSAKeyValue>

Both, of course, provide the same modulus.

Another possibility is that in the C# code the PEM key is imported directly . In .NET Core, as of version 3.0, the RSA.ImportSubjectPublicKeyInfo() method is available to import a DER encoded key in X.509/SPKI format. The DER encoding results from the PEM encoded key by removing header, footer and line breaks and Base64 decoding the rest. In lower .NET Core versions or in .NET Framework the import of PEM keys is supported by BouncyCastle.

With the correct modulus, the C# code provides a correct ciphertext.


Note that the Python and JavaScript code use a different padding than the C# code. The Python and JavaScript code apply PKCS#1 v1.5 padding, while the C# code uses OAEP. For the C# code to also apply PKCS#1 v1.5, RSACryptoServiceProvider.Encrypt() must pass a false in the second parameter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM