C # DECRYPT file using RSA DER format. Public key

I have seen many questions, none of them give good answers, or if they try, they assume that the one who asks the question does not ask what he really is asking. And just for the record, I DO NOT ask about signing, encryption or PEM files!

In my case, I will get a small file with encrypted data. It was encrypted using the RSA key pair private key.

The public key that I have is a DER file in ASN.1 format, it is not a certificate as such and is not signed.

In Java this is easy, in C # it is a nightmare from what I can say. X509Certificate2 states that “object not found” when I try to parse its byte array of key.

Keys were generated using the following openSSL commands:

>openssl genrsa -out private_key.pem 2048

Generating RSA private key, 2048 bit long modulus
...........+++
....................................................................................................
...........................+++
e is 65537 (0x10001)

>openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt

>openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der
writing RSA key

Edit: The code I'm trying is:

private byte[] ReadBytesFromStream(string streamName)
{
    using (Stream stream = this.GetType().Assembly.GetManifestResourceStream(streamName))
    {
        byte[] result = new byte[stream.Length];
        stream.Read(result, 0, (int) stream.Length);
        return result;
    }
}

public void LoadPublicKey()
{
    byte[] key = ReadBytesFromStream("my.namespace.Resources.public_key.der");
    X509Certificate2 myCertificate;
    try
    {
        myCertificate = new X509Certificate2(key);
    }
    catch (Exception e)
    {
        throw new CryptographicException(String.Format("Unable to open key file. {0}", e));
    } 
}

The ReadBytesFromStream method returns the correct byte stream, the public_key.der file is an embedded resource.

+3
source share
1 answer

Just to polish it. However, the code below is still a little dirty, but it looks like I could work.

The reason we cannot use public keys to decrypt a message on Windows is explained here: http://www.derkeiler.com/Newsgroups/microsoft.public.dotnet.security/2004-05/0270.html

#, -, , . Base64 . , Windows . , , , .

, , , Windows (#). StackOverflow , Windows . Android Dot Net (#)

, Java, #. stripLeadingZeros , :

  private static byte[] stripLeadingZeros(byte[] a) {
    int lastZero = -1;
    for (int i = 0; i < a.length; i++) {
      if (a[i] == 0) {
        lastZero = i;
      }
      else {
        break;
      }
    }
    lastZero++;
    byte[] result = new byte[a.length - lastZero];
    System.arraycopy(a, lastZero, result, 0, result.length);
    return result;
  }

:

$ openssl genrsa -out private_key.pem 2048

$ openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt

$ openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der

Java:

package com.example.signing;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import jcifs.util.Base64;

public class SigningExample {
    private static String PRIVATE_KEY_FILE = "private_key.der";
    private static String PUBLIC_KEY_FILE  = "public_key.der";

    /**
     * @param args
     */
    public static void main(String[] args) {
        SigningExample.sign();
    }

    private static void sign() {
        try {
            String text = new String(SigningExample.loadFromFile("message.xml"));
            String message = Base64.encode(text.getBytes());

            RSAPrivateKey privateKey = PrivateRSAKeyReader.getKeyFile(SigningExample.PRIVATE_KEY_FILE);
            RSAPublicKey publicKey = PublicRSAKeyReader.getKeyFile(SigningExample.PUBLIC_KEY_FILE);

            byte[] modulusBytes = publicKey.getModulus().toByteArray();
            byte[] exponentBytes = publicKey.getPublicExponent().toByteArray();

            modulusBytes = SigningExample.stripLeadingZeros(modulusBytes);

            String modulusB64 = Base64.encode(modulusBytes);
            String exponentB64 = Base64.encode(exponentBytes);

            System.out.println("Copy these two into your c# code:");
            System.out.println("DotNet Modulus : " + modulusB64);
            System.out.println("DotNet Exponent: " + exponentB64);

            // Testing
            byte[] signature = SigningExample.sign(message.getBytes(), privateKey, "SHA1withRSA");

            String signedMessage = message + "\n" + Base64.encode(signature);

            SigningExample.saveToBase64File("message.signed", signedMessage.getBytes());

            System.out.println("\nMessage  :\n" + signedMessage);

            String[] newkey = new String(SigningExample.loadFromBase64File("message.signed")).split("\\n");
            System.out.println("Verified : " + SigningExample.verify(newkey[0].getBytes(), publicKey, "SHA1withRSA", Base64.decode(newkey[1])));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static byte[] stripLeadingZeros(byte[] a) {
        int lastZero = -1;
        for (int i = 0; i < a.length; i++) {
            if (a[i] == 0) {
                lastZero = i;
            } else {
                break;
            }
        }
        lastZero++;
        byte[] result = new byte[a.length - lastZero];
        System.arraycopy(a, lastZero, result, 0, result.length);
        return result;
    }

    private static byte[] sign(byte[] data, PrivateKey prvKey,
            String sigAlg) throws Exception {
        Signature sig = Signature.getInstance(sigAlg);
        sig.initSign(prvKey);
        sig.update(data, 0, data.length);
        return sig.sign();
    }

    private static boolean verify(byte[] data, PublicKey pubKey,
            String sigAlg, byte[] sigbytes) throws Exception {
        Signature sig = Signature.getInstance(sigAlg);
        sig.initVerify(pubKey);
        sig.update(data, 0, data.length);
        return sig.verify(sigbytes);
    }

    public static void saveToBase64File(String fileName, byte[] data) throws IOException {
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));

        try {
            String b64 = Base64.encode(data);
            int lineLength = 64;
            int idx = 0;
            int len = b64.length();

            while (len - idx >= lineLength) {
                out.write(b64.substring(idx, idx + lineLength).getBytes());
                out.write('\n');
                idx += lineLength;
            }
            out.write(b64.substring(idx, len).getBytes());
        } catch (Exception e) {
            throw new IOException("Unexpected error", e);
        } finally {
            out.close();
        }
    }

    public static byte[] loadFromBase64File(String fileName) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(fileName));

        try {
            StringBuffer sb = new StringBuffer();

            String buffer;

            while ((buffer = br.readLine()) != null) {
                sb.append(buffer);
            }

            return Base64.decode(sb.toString());
        } catch (Exception e) {
            throw new IOException("Unexpected error", e);
        } finally {
            br.close();
        }
    }

    public static void saveToFile(String fileName, byte[] data) throws IOException {
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));

        try {
            out.write(data);
        } catch (Exception e) {
            throw new IOException("Unexpected error", e);
        } finally {
            out.close();
        }
    }

    public static byte[] loadFromFile(String fileName) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(fileName));

        try {
            StringBuffer sb = new StringBuffer();

            String buffer;

            while ((buffer = br.readLine()) != null) {
                sb.append(buffer);
            }

            return sb.toString().getBytes();
        } catch (Exception e) {
            throw new IOException("Unexpected error", e);
        } finally {
            br.close();
        }
    }
}

class PrivateRSAKeyReader {

    public static RSAPrivateKey getKeyFile(String filename) throws Exception {

        File f = new File(filename);
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        byte[] keyBytes = new byte[(int) f.length()];
        dis.readFully(keyBytes);
        dis.close();

        return PrivateRSAKeyReader.generateKey(keyBytes);
    }

    public static RSAPrivateKey getKey(String base64) throws Exception {
        byte[] keyBytes = Base64.decode(base64);

        return PrivateRSAKeyReader.generateKey(keyBytes);
    }

    private static RSAPrivateKey generateKey(byte[] keyBytes) throws Exception {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(spec);
    }
}

class PublicRSAKeyReader {

    public static RSAPublicKey getKeyFile(String filename) throws Exception {

        File f = new File(filename);
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        byte[] keyBytes = new byte[(int) f.length()];
        dis.readFully(keyBytes);
        dis.close();

        return PublicRSAKeyReader.generateKey(keyBytes);
    }

    public static RSAPublicKey getKey(String base64) throws Exception {
        byte[] keyBytes = Base64.decode(base64);

        return PublicRSAKeyReader.generateKey(keyBytes);
    }

    private static RSAPublicKey generateKey(byte[] keyBytes) throws Exception {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(spec);
    }
}

# :

String signedMessage = ""; // load Base64 coded the message generated in Java here.

byte[] message = Convert.FromBase64String(signedMessage);
String messageString = Encoding.ASCII.GetString(message);

String[] lines = Regex.Split(messageString, "\n");

byte[] content = Convert.FromBase64String(lines[0]); // first line of the message were the content
byte[] signature = Convert.FromBase64String(lines[1]); // second line were the signature

RSACryptoServiceProvider rsaObj = new RSACryptoServiceProvider(2048);

//Create a new instance of the RSAParameters structure.
RSAParameters rsaPars = new RSAParameters();

rsaPars.Modulus = Convert.FromBase64String("insert your modulus revealed in the Java example here");
rsaPars.Exponent = Convert.FromBase64String("AQAB"); // Exponent. Should always be this.

// Import key parameters into RSA.
rsaObj.ImportParameters(rsaPars);

// verify the message
Console.WriteLine(rsaObj.VerifyData(Encoding.ASCII.GetBytes(lines[0]), "SHA1", signature));

:

using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

, Base64 .

0

All Articles