2012-04-24 3 views
3

많은 질문을 보았습니다. 아무도 실제로 좋은 대답을 제공하지 못했습니다. 또는 시도 할 때 질문을하는 사람이 실제로 묻는 질문을하지 않는 것으로 가정합니다 . 그리고 기록을 위해 서명, 암호화 또는 PEM 파일에 대해 묻지 않습니다!C# DECRYPT RSA DER 형식을 사용하는 파일 공개 키

내 경우에는 암호화 된 데이터의 작은 파일을 받게 될 것입니다. RSA 키 쌍의 개인 키를 사용하여 암호화되었습니다.

사용할 수있는 공개 키는 ASN.1 형식의 DER 파일이며 인증서가 아니기 때문에 서명되지 않았습니다.

Java에서는 쉽게 할 수 있습니다. C#에서는 내가 말할 수있는 것에서 악몽입니다. X509Certificate2에서 "개체를 찾을 수 없습니다"라는 메시지가 표시되면 키의 바이트 배열을 구문 분석하려고합니다.

키는 다음 OpenSSL을 사용하여 생성 된 것은 명령 :

>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 

편집 : 코드는 내가 노력하고있어 :

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)); 
    } 
} 

ReadBytesFromStream 방법은 정확한 바이트 스트림의 PUBLIC_KEY를 반환 않습니다. der 파일은 임베디드 리소스입니다.

+0

시도하고있는 'C#'코드를 보여주십시오. – ja72

+0

철저한 googeling에, 나는 메시지를 암호문을 해독하기 위하여 공개 RSA 열쇠를 사용하여 MS가 당신을시키는 것을 제외하고 2 개의 결점이,다는 것을 부탁에왔다. RSA는 modulus/key와 같은 크기의 경합 만 처리 할 수 ​​있습니다. 2048의 경우이 제한은 245 자입니다. –

+0

개인 키로 암호화 할 때는 실제로 서명해야합니다. 어쨌든 누구나 잠재적으로 콘텐츠를 읽을 수 있으므로 서명을 사용하여 콘텐츠가 1인지 확인해야합니다. 개인 키의 소유자로부터 오는 것입니다. , 2)는 수정되지 않았습니다. –

답변

0

그냥 닦으세요. 아래의 코드는 여전히 약간 지저분하지만 그래도 작동 할 수있는 것 같습니다.

우리는 Windows의 메시지가 여기에 설명되어 해독하는 공개 키를 사용할 수없는 이유 : 그것을, 이 http://www.derkeiler.com/Newsgroups/microsoft.public.dotnet.security/2004-05/0270.html

다음, 당신이 어딘가에, C# 코드의 공개 키 계수와 지수를 필요로 할 파일 또는 임베디드는 실제로 여기의 문제가 아닙니다. Base64를 사용하여 이진 키를 마무리합니다. Windows가 실제로 가져올 키를 생성하는 것을 포기했습니다. 게다가, 내가 필요로하는 것을 위해 공개 키는 임베디드 리소스가 될 것입니다.

내가 가진 마지막 문제는 키에서 생성 된 계수가 Windows (C#)에서 작동하지 않는다는 것입니다. 이 StackOverflow 포스트는 Windows의 모듈이 앞에 0을 포함 할 수 없다는 것을 해결하기위한 열쇠를 가졌습니다. Android in-app billing Verification of Receipt in Dot Net(C#)

Java에서 생성 된 계수는 C#에서 작동하지 않았습니다. 작업 공개 키 계수 만들기 위해 해당 게시물에서 stripLeadingZeros 코드를 사용

$ 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 

자바 코드 :

우선 들어

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; 
    } 

를이 내가 키 파일을 생성하는 방법이다

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); 
    } 
} 

이 코드 조각은 다음 트릭을 수행해야합니다.

,210
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로 다른 계층에 최종 메시지를 포장하는 것은 조금 잔인한 변경 될 것을 인정한다.

+1

답변 인 경우 _accepted_로 표시하십시오. –

관련 문제