2012-02-14 68 views
16

Tóm lại, đây là vấn đề của tôi:Sử dụng Base64 mã hóa Public Key để xác minh chữ ký RSA

private string publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFOGwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWpbY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5yGPhGAAmqYrm8YiupwQIDAQAB"; 

/* Some transformation required, using publicKeyString to initiate a new RSACryptoServiceProvider object 
*/ 

//for now: 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 

byte[] selfComputedHash = new byte[]; //left out of the example 
byte[] signature = new byte[]; 

bool result = rsa.VerifyHash(selfComputedHash, CryptoConfig.MapNameToOID("SHA1"), signature); 

Như bạn có thể thấy, vấn đề là bắt đầu một RSACryptoServiceProvider mới với trao Base64 mã hóa chuỗi khóa công khai. Tôi đã có thể làm instantiation bằng cách sử dụng một đối tượng RSAParameters, nạp với byte [] 's cho Modulus và Exponent bắt nguồn từ chuỗi khóa công khai này bằng cách sử dụng một lệnh shell OpenSSL. Nhưng vì khóa công khai này có thể thay đổi trong tương lai, tôi muốn có thể lưu trữ nó ở dạng ban đầu trong cơ sở dữ liệu. Phải có một cách đơn giản hơn để giải quyết vấn đề này. Rất nhiều ví dụ tôi đã đọc cho đến nay tránh được vấn đề này bằng cách xuất và nhập khóa riêng tư và công khai được tạo ra và từ đối tượng chứa khóa và sử dụng nó trong cùng một đoạn mã và do đó không 'chuyển 'chìa khóa trong một số hình thức chuỗi ra khỏi bộ nhớ. Một số người đã bày tỏ cùng một vấn đề, cả ở đây trên StackOverflow và trên các trang web khác, nhưng tôi đã không thể tìm thấy một câu trả lời thỏa mãn được nêu ra.

Bất kỳ ý tưởng nào đều được hoan nghênh.

Thông tin cơ bản: Đối tác truyền thông của tôi tính toán hàm băm SHA1 20 byte từ chuỗi đầu vào có độ dài thay đổi, bao gồm thông tin chứa trong một số trường của thông báo được mã hóa ASCII. Băm này sau đó được ký RSA với khóa riêng của đối tác của tôi và được gửi cùng với thông báo ASCII cho tôi. Khi đến, tôi tính toán bản thân hàm băm SHA1, sử dụng cùng các trường từ thông báo ASCII và sau đó thử xác minh xem các trường này không bị thay đổi bằng cách gọi VerifyHash.

Khóa được cung cấp ở 2 dạng: thông thường và 'noNL'. Phiên bản noNL được bao gồm trong đoạn mã trên, phiên bản thường là thế này:

-----BEGIN PUBLIC KEY----- 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO 
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp 
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y 
GPhGAAmqYrm8YiupwQIDAQAB 
-----END PUBLIC KEY----- 

Trả lời

13

chuỗi của bạn là mã hóa base64 của một SubjectPublicKeyInfo. Bạn có thể sử dụng Bouncycastle.net để giải mã nó như thế này:

byte[] publicKeyBytes = Convert.FromBase64String(publicKeyString); 
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes); 
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter; 
RSAParameters rsaParameters = new RSAParameters(); 
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(); 
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned(); 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
rsa.ImportParameters(rsaParameters); 
+0

Cảm ơn bạn, điều đó khá dễ dàng. Tôi sẽ xem xét thư viện BouncyCastle, nhưng bạn có chắc chắn không có cách nào để thực hiện điều này chỉ bằng cách sử dụng thư viện Mật mã trong .NET không? – jscheppers

+0

@jscheppers: Bạn có thể thực hiện thủ công như poupou gợi ý, nhưng không có hỗ trợ trực tiếp cho định dạng trong .NET. Một tìm kiếm nhanh cho thấy ví dụ này để giải mã thủ công: http://www.jensign.com/JavaScience/dotnet/pempublic/pempublic.cs, nhưng việc này có vẻ lộn xộn một chút. –

+0

Tôi nghĩ rằng tôi thích giải pháp BouncyCastle của bạn sau đó;) Tôi đã thử nó trong thực hiện hiện tại của tôi và nó hoạt động. Tôi sẽ đánh dấu bài đăng của bạn là câu trả lời! – jscheppers

4

Trước base64 chỉ là một mã hóa của một số dữ liệu nhị phân. Có nhiều cách để mã hóa, dưới dạng nhị phân, một khóa công khai RSA. Tuy nhiên nếu bạn có được điều này từ OpenSSL, nó có thể là cấu trúc RSAPublicKey được mã hóa bởi DER.

RSAPublicKey ::= SEQUENCE { 
    modulus   INTEGER, -- n 
    publicExponent  INTEGER } -- e 

Nói chung bạn sẽ cần một bộ giải mã ASN.1, Mono.Security.dll cung cấp one, nhưng đối với một cấu trúc đơn giản như vậy bạn có thể muốn làm điều đó bằng tay từ ASN.1 cơ bản là một Tag, Chiều dàiGiá trị.

+0

Tổ chức cung cấp các khóa công khai không đề cập đến định dạng của chìa khóa, nhưng kể từ khi tôi có thể 'đọc' chúng với OpenSSL và từ khóa chứa cả hai ----- BEGIN PUBLIC KEY ----- và ----- END PUBLIC KEY ----- tags (Tôi sẽ thêm nó vào bài viết gốc của mình) Tôi khá chắc chắn đó là một mã hóa DER Chìa khóa. Bạn sẽ chuyển đổi chuỗi này thành cấu trúc ASN.1 bằng tay như thế nào? Khi byte đi vào chơi, tôi không chắc chắn về bản thân mình :) – jscheppers

+1

Lưu ý rằng nó thực sự là một 'SubjectPublicKeyInfo' * chứa * một' RSAPublicKey'. –

0

Nếu đối tác của bạn cũng sử dụng .NET, anh/cô ấy có thể lấy từ makecert https://github.com/mono/mono/blob/bf55818da11240bd108dc51b374fae3d3b5482ce/mcs/tools/security/makecert.cs của Mono để tạo tệp chứng chỉ và gửi trực tiếp cho bạn.

Trong trường hợp đó, bạn có thể dễ dàng nạp giấy chứng nhận thay vì byte thô,

http://www.lextm.com/2012/02/simple-publicprivate-key-signing-sample-code/

+0

Đó sẽ là một khả năng tốt, nhưng tôi không có quyền kiểm soát cách mà các phím được tạo ra. Các phím được cung cấp như hiện tại, không có giấy chứng nhận nào có sẵn chìa khóa này. – jscheppers

Các vấn đề liên quan