TL; DR; Tôi đã không tìm thấy cách lấy được khóa đối xứng bằng KDF được mô tả trong NIST SP 800-56A, mục 5.8.1 sử dụng các lớp tích hợp trong .NET 4.0. là nó có thể trong .NET 4.0 sử dụng thư viện BouncyCastle đáng yêu (NuGet: Install-Package BouncyCastle-Ext -Version "1.7.0"). Đây là cách:
Bước 1: Nhận bên kia của công chúng chính
Tùy thuộc vào kịch bản của bạn, điều này có thể được đọc từ một giấy chứng nhận hoặc đến với bạn như là một phần của thông điệp có chứa các dữ liệu được mã hóa. Một khi bạn có Base64 mã hóa khóa công khai, đọc nó vào một Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters đối tượng như vậy:
var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr);
ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
Bước 2: Đọc bạn tin-key
này sẽ most- thường liên quan đến việc đọc khóa riêng tư từ chứng chỉ PFX/P12. Tài khoản windows đang chạy mã nên có quyền truy cập vào PFX/P12 và bổ sung, nếu chứng chỉ được nhập vào một kho chứng chỉ, bạn sẽ cần cấp quyền thông qua All Tasks -> quản lý menu khóa riêng trong certmgr.msc
using (StreamReader reader = new StreamReader(path))
{
var fs = reader.BaseStream;
string password = "<password for the PFX>";
Pkcs12Store store = new Pkcs12Store(fs, passWord.ToCharArray());
foreach (string n in store.Aliases)
{
if (store.IsKeyEntry(n))
{
AsymmetricKeyEntry asymmetricKey = store.GetKey(n);
if (asymmetricKey.Key.IsPrivate)
{
ECPrivateKeyParameters privateKey = asymmetricKey.Key as ECPrivateKeyParameters;
}
}
}
}
BƯỚC 3: tính bí mật
IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH");
aKeyAgree.Init(privateKey);
BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey);
byte[] sharedSecretBytes = sharedSecret.ToByteArray();
BƯỚC 4 chia sẻ: Chuẩn bị thông tin cần thiết để tính toán khóa đối xứng:
byte[] algorithmId = Encoding.ASCII.GetBytes(("<prependString/Hex>" + "id-aes256-GCM"));
byte[] partyUInfo = Encoding.ASCII.GetBytes("<as-per-agreement>");
byte[] partyVInfo = <as-per-agreement>;
MemoryStream stream = new MemoryStream(algorithmId.Length + partyUInfo.Length + partyVInfo.Length);
var sr = new BinaryWriter(stream);
sr.Write(algorithmId);
sr.Flush();
sr.Write(partyUInfo);
sr.Flush();
sr.Write(partyVInfo);
sr.Flush();
stream.Position = 0;
byte[] keyCalculationInfo = stream.GetBuffer();
Bước 5: Rút ra các sy mmetric key
// NOTE: Use the digest/Hash function as per your agreement with the other party
IDigest digest = new Sha256Digest();
byte[] symmetricKey = new byte[digest.GetDigestSize()];
digest.Update((byte)(1 >> 24));
digest.Update((byte)(1 >> 16));
digest.Update((byte)(1 >> 8));
digest.Update((byte)1);
digest.BlockUpdate(sharedSecret, 0, sharedSecret.Length);
digest.BlockUpdate(keyCalculationInfo, 0, keyCalculationInfo.Length);
digest.DoFinal(symmetricKey, 0);
Bây giờ bạn có khóa đối xứng sẵn sàng thực hiện giải mã. Để thực hiện giải mã bằng AES, BouncyCastle IWrapper có thể được sử dụng. Lấy IWrapper bằng cách sử dụng Org.BouncyCastle.Security.WrapperUtilities bằng cách gọi WrapperUtilities.GetWrapper ("AES //"), ví dụ: "AES/CBC/PKCS7". Điều này cũng sẽ phụ thuộc vào thỏa thuận giữa hai bên giao tiếp.
Khởi tạo mật mã (IWrapper) bằng khóa đối xứng và vectơ khởi tạo (IV) và gọi phương thức Unwrap để nhận byte thuần văn bản. Cuối cùng, chuyển đổi thành chuỗi ký tự bằng cách sử dụng mã hóa ký tự được sử dụng (ví dụ: UTF8/ASCII/Unicode)
Về phía mã hóa, BouncyCastle có lớp ConcatenationKDFGenerator https://github.com/bcgit/bc-csharp/blob/0801c1543f0cafc79c44b225e53c973bdd1b0a0f/ crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs – Sentinel