I am new to cryptography. I have an api provided by a bank. The banks says that they are using RSA algorithm with 2048 bits. We used this api first to get the public key. Here is the sample public key(some chars updated for security),


This look like Base 64 string. The length is 397. I am assuming that this is Modulus and Exponent is AQAB. When I convert this Base64 into bytes it become 294 and (294 * 8)2352 bits. Why 2352 and not 2048 bits?

Actually, I am encrypting an string and sending to Bank api both in Java and in C#. In Java I am doing,

public class RSAUtility {
public static String encrypt(String plainText, String key){
        PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)));
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return Base64.encodeToString(cipher.doFinal(plainText.getBytes("UTF-8")),Base64.DEFAULT);
    }catch (Exception e) {
    return null;

It works very well in java. But in C# I am doing this and it does not work. Any expert can please help me.

var keyXml = "<RSAKeyValue><Modulus>" + key + "</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

EncrptedValue = CryptUtils.Encrypt(keyXml, "MyString", RsaKeyLengths.Bit2048);

    public static string Encrypt(string publicKey, string data, RsaKeyLengths length = RsaKeyLengths.Bit2048)
        // full array of bytes to encrypt
        byte[] bytesToEncrypt;

        // worker byte array
        byte[] block;

        // encrypted bytes
        byte[] encryptedBytes;

        // length of bytesToEncrypt
        var dataLength = 0;

        // number of bytes in key                
        var keySize = 0;

        // maximum block length to encrypt          
        var maxLength = 0;

        // how many blocks must we encrypt to encrypt entire message?
        var iterations = 0;

        // the encrypted data
        var encryptedData = new StringBuilder();

        // instantiate the crypto provider with the correct key length
        var rsaCryptoServiceProvider = new RSACryptoServiceProvider((int)length);

        // initialize the RSA object from the given public key

        // convert data to byte array
        bytesToEncrypt = Encoding.Unicode.GetBytes(data);

        // get length of byte array
        dataLength = bytesToEncrypt.Length;

        // convert length of key from bits to bytes
        keySize = (int)length / 8;

        // .NET RSACryptoServiceProvider uses SHA1 Hash function
        // use this to work out the maximum length to encrypt per block
        maxLength = ((keySize - 2) - (2 * SHA1.Create().ComputeHash(bytesToEncrypt).Length));

        // how many blocks do we need to encrypt?
        iterations = dataLength / maxLength;

        // encrypt block by block
        for (int index = 0; index <= iterations; index++)
            // is there more than one full block of data left to encrypt?
            if ((dataLength - maxLength * index) > maxLength)
                block = new byte[maxLength];
                block = new byte[dataLength - maxLength * index];

            // copy the required number of bytes from the array of bytes to encrypt to our worker array
            Buffer.BlockCopy(bytesToEncrypt, maxLength * index, block, 0, block.Length);

            // encrypt the current worker array block of bytes
            encryptedBytes = rsaCryptoServiceProvider.Encrypt(block, true);

            // RSACryptoServiceProvider reverses the order of encrypted bytesToEncrypt after encryption and before decryption.
            // Undo this reversal for compatibility with other implementations

            // convert to base 64 string

        return encryptedData.ToString();

1 Answer 1


Possibly partial answer.

First an aside: you don't need to "secure" a public key by changing bits; the whole purpose and point of public-key cryptography is that it is secure even though the public key is public, which includes available to adversaries.

That publickey form you have is NOT just "modulus and exponent". It is true that the last 3 bytes in this case are the exponent, and by luck the total key encoding happens to be a multiple of 3 so those 3 bytes are the last 4 chars of base64. If you are treating the other 294-3 bytes as the modulus that is very wrong.

What you do have, as you correctly stated in the JCA calls, is what Java calls an X509EncodedKeySpec and in standard terms is the SubjectPublicKeyInfo structure defined in the (very widely used) X.509 standard. That structure is an ASN.1 SEQUENCE containing an AlgorithmIdentifier which identifies the algorithm using another SEQUENCE this time of an OBJECT IDENTIFIER aka OID or OBJECT which in this case is an OID for RSA and (usually) a parameters field of varying type which in this case is NULL, all of that followed by a BIT STRING containing the algorithm-specific encoding of the publickey value, which for RSA is defined by PKCS#1 as used in rfc3279 or its update rfc4055, and is a(nother) SEQUENCE of two INTEGERs which are the modulus and (public) exponent respectively. Every piece of an ASN.1 structure has its own (smallish) "type and length" header.

To be concrete, the value of your "secured" (and presumably wrong) publickey can easily be seen with the openssl command line utility asn1parse on your data. The (outer) SPKI sequence of AlgId plus bitstring:

c:\work>openssl asn1parse <temp.b64
    0:d=0  hl=4 l= 290 cons: SEQUENCE
    4:d=1  hl=2 l=  13 cons: SEQUENCE
    6:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption
   17:d=2  hl=2 l=   0 prim: NULL
   19:d=1  hl=4 l= 271 prim: BIT STRING

The (inner) RSAPublicKey within the bitstring (with the number values in hex):

c:\work>openssl asn1parse <temp.b64 -strparse 19
    0:d=0  hl=4 l= 266 cons: SEQUENCE
    4:d=1  hl=4 l= 257 prim: INTEGER           :82ABE649C9EF606A50F9EC467BD38CDA
  265:d=1  hl=2 l=   3 prim: INTEGER           :010001

I presume if you take the part of your actual publickey that is the modulus and represent it in base64 in the <Modulus> element that will work, but I don't do dot-NET myself.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .