문제

Bouncycastle RSA 키 쌍을 생성하는 기능이 있습니다. 개인 키를 암호화 한 다음 암호화 된 개인 및 공개 키를 별도의 SQL2008 데이터베이스 필드에 저장해야합니다.

키프레드를 얻기 위해 다음을 사용하고 있습니다.

private static AsymmetricCipherKeyPair createASymRandomCipher()
{
    RsaKeyPairGenerator r = new RsaKeyPairGenerator();
    r.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
    AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
    return keys; 
}

이것은 키를 잘 반환하고 있지만 개인 키를 암호화하고 데이터베이스에 저장할 수있는 방법은 확실하지 않습니다.

이것이 제가 현재 데이터 암호화를 사용하고있는 것입니다 (잘못?).

public static byte[] encBytes2(AsymmetricKeyParameter keyParam, byte[] Key, byte[] IV)
{
    MemoryStream ms = new MemoryStream();
    Rijndael rjdAlg = Rijndael.Create();
    rjdAlg.Key = Key;
    rjdAlg.IV = IV;
    CryptoStream cs = new CryptoStream(ms, rjdAlg.CreateEncryptor(), CryptoStreamMode.Write);
    byte[] keyBytes = System.Text.Encoding.Unicode.GetBytes(keyParam.ToString());
    cs.Write(keyBytes, 0, keyBytes.Length);
    cs.Close();
    byte[] encryptedData = ms.ToArray();
    return encryptedData;
}

KeyParam.tostring ()을 변환하는 KeyBytes 설정은 실제 값이 아니라 키패라미터 이름 만 변환하므로 올바르게 맞지 않습니다. 이 기능에 Keys.private의 이전 키 쌍의 리턴을 제출합니다.

다른 질문은 공개 키를 암호화하지 않기 때문에 SQL2008 데이터베이스, NVarchar (256) 또는 기타에 어떤 형식을 저장해야합니까?

모든 도움은 대단히 감사하겠습니다.

도움이 되었습니까?

해결책

명확 해야하는 이유로, 기본 (그리고 아마도 부주의 한) 직렬화는 매우 제한된 상황에서만 작성 해야하는 개인 키와 잘 어울리지 않습니다.

Bouncycastle은 PKCS#8을 지원하는데, 이는 개인 키 "직렬화"의 관련 표준입니다. PrivateKeyInfo 및 암호화 프리 테 키인포 (EncryptedPrivatekeyInfo)라는 구조가 있습니다. 그들은 ASN에 있기 때문에 1이 그들을 직렬화/사제 화하는 표준 방법이 있습니다. 이름에서 알 수 있듯이 키를 일반 텍스트로 저장하고 다른 하나는 비밀번호를 기반으로 키를 암호화합니다.

공개 키의 경우 - 일반적으로 암호화되지 않습니다. BC는 X.509 표준 형식의 SubjectPublickeyInfo를 지원합니다.

C# 빌드에서 볼 수있는 높은 수준의 클래스는 다음과 같습니다.

  • org.bouncycastle.security.privatekeyfactory
  • org.bouncycastle.security.publickeyfactory
  • org.bouncycastle.pkcs.encryptedprivatekeyinfoffactory
  • org.bouncycastle.pkcs.privatekeyinfoffactory
  • org.bouncycastle.x509.subjectpublickeyInfoffofactory

다른 팁

객체가 직렬화 가능한 것으로 표시되는 한, 객체를 바이트 어레이로 변환하는 한 가지 방법은 .NET에서 BinaryFormatter 클래스를 사용하는 것입니다.

이 명령문을 사용하여 코드 파일에 추가해야합니다.

using System.Runtime.Serialization.Formatters.Binary;

이진 형성자는 클래스를 스트림에 출력 할 수 있습니다. 객체를 바이트 어레이로 변환하려고 할 때 System.io.memorystream을 임시 저장소로 사용할 수 있습니다.

MemoryStream memStream = new MemoryStream();

그런 다음 새 이진 포피터를 만들 수 있습니다.

BinaryFormatter formatter = new BinarryFomatter();

그리고 이것을 사용하여 객체를 직렬화하십시오.

formatter.Serialize(memStream, someObject);

바이트를 얻으려면 사용할 수 있습니다.

return memStream.ToArray();

바이트 배열을 제조하려면 바이트를 메모리 스트림에 작성해야합니다.

memStream.Write(arrBytes, 0, arrBytes.Length);

스트림의 시작 부분으로 돌아갑니다.

memStream.Seek(0, SeekOrigin.Begin);

그런 다음 Formatter를 사용하여 물체를 재현하십시오.

Object obj = (Object)formatter.Deserialize(memStream);

이미 암호화 기능을 사용하는 경우 데이터베이스에 저장하기 전에 생성 된 바이트 배열을 아주 쉽게 암호화 할 수 있어야합니다.

바라건대 그것은 올바른 방향으로 당신을 도울 것입니다. 운이 좋으면 바운시 캐스트 객체는 직렬화 가능으로 표시되며 추가 코드가 필요하지 않으면 추가 코드가 필요합니다. 나중에, 나는이를 테스트 할 수 있도록 Bouncycastle 라이브러리를보고 필요한 경우 더 많은 코드를 게시 할 수 있습니다.


... 나는 전에 Bouncycastle을 사용한 적이 없습니다. 일부 테스트 후 공개 및 개인 주요 객체는 직렬화 할 수없는 것으로 보이므로 이러한 객체를 그대로 변환해야합니다!

공개 및 개인 키는 속성을 다양한 Bouncycastle.math.biginteger 값으로 노출시키는 것으로 보입니다. (열쇠는이 bigintegers로부터 구성 할 수도 있습니다). 또한 BigIntegers는 TobyTearRay () 기능을 가지고 있으며 바이트 배열로 구성 할 수도 있습니다. 매우 유용한..

각 키를 BigIntegers로 나누고 바이트 배열로 차례로 나눌 수 있고 그 반대가 가능하다는 것을 알면이 모든 것을 직렬화 가능한 객체에 저장하는 방법이 있습니다. 간단한 구조 또는 수업은 예를 들어됩니다

[Serializable]
private struct CipherPrivateKey
{
    public byte[] modulus;
    public byte[] publicExponent;
    public byte[] privateExponent;
    public byte[] p;
    public byte[] q;
    public byte[] dP;
    public byte[] dQ;
    public byte[] qInv;
}

[Serializable]
private struct CipherPublicKey
{
    public bool isPrivate;
    public byte[] modulus;
    public byte[] exponent;
}

이것은 우리에게 사용하기 쉬운 직렬화 가능한 객체를 제공합니다.

Asymmetriccipherkeypair는 공개 및 개인 키를 비대칭 케이 파라미터 객체로 노출시킵니다. 더 자세한 속성을 얻으려면 다음과 같은 속성을 캐스팅해야합니다.

kyypair.public to bouncycastle.crypto.parameters.rsakeyparameters kyypair.private to bouncycastle.crypto.parameters.rsaprivatecrtkeyparameters

다음 기능은 이들을 앞서 선언 한 것으로 스트루크로 변환합니다.

private static CipherPublicKey getCipherPublicKey(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters cPublic)
{
    CipherPublicKey cpub = new CipherPublicKey();
    cpub.modulus = cPublic.Modulus.ToByteArray();
    cpub.exponent = cPublic.Exponent.ToByteArray();
    return cpub;
}
private static CipherPrivateKey getCipherPrivateKey(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters cPrivate)
{
    CipherPrivateKey cpri = new CipherPrivateKey();
    cpri.dP = cPrivate.DP.ToByteArray();
    cpri.dQ = cPrivate.DQ.ToByteArray();
    cpri.modulus = cPrivate.Modulus.ToByteArray();
    cpri.p = cPrivate.P.ToByteArray();
    cpri.privateExponent = cPrivate.Exponent.ToByteArray();
    cpri.publicExponent = cPrivate.PublicExponent.ToByteArray();
    cpri.q = cPrivate.Q.ToByteArray();
    cpri.qInv = cPrivate.QInv.ToByteArray();
    return cpri;
}

앞에서 언급 한 바이너리 포맷터를 사용하여 방금 만든 직렬화 가능한 객체를 바이트 어레이로 변환 할 수 있습니다.

CipherPublicKey cpub = getCipherPublicKey((Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keypair.Public);
MemoryStream memStream = new MemoryStream();
BinaryFormatter formatter = new BinarryFomatter();
formatter.Serialize(memStream, cpub);
return memStream.ToArray();

그런 다음 앞에서 설명한 바와 같이 디시 리아 화는 역수입니다. 공공 또는 개인 스트러크가 사형화 된 후에는 바운시 캐슬 대기업자를 사용하여 열쇠를 재현 할 수 있습니다. 이러한 기능은 이것을 보여줍니다.

private static Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters recreateASymCipherPublicKey(CipherPublicKey cPublicKey)
{
    Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters key;
    key = new Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters(
            cPublicKey.isPrivate,
            createBigInteger(cPublicKey.modulus),
            createBigInteger(cPublicKey.exponent));
    return key;
}

private static Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters recreateASymCipherPrivateKey(CipherPrivateKey cPrivateKey)
{
    Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key;
    key = new Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters(
            createBigInteger(cPrivateKey.modulus),
            createBigInteger(cPrivateKey.publicExponent),
            createBigInteger(cPrivateKey.privateExponent),
            createBigInteger(cPrivateKey.p),
            createBigInteger(cPrivateKey.q),
            createBigInteger(cPrivateKey.dP),
            createBigInteger(cPrivateKey.dQ),
            createBigInteger(cPrivateKey.qInv));
    return key;
}

어떤 이유로 든 원래 키 쌍을 재현 해야하는 경우 :

AsymmetricKeyParameter publ = (AsymmetricKeyParameter)recreateASymCipherPublicKey(cKeyPair.publicKey);
AsymmetricKeyParameter priv = (AsymmetricKeyParameter)recreateASymCipherPrivateKey(cKeyPair.privateKey);
AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(publ, priv);

바라건대 모든 것이 의미가 있습니다! 코드 샘플이 도움이됩니다.

올바른 접근법은 Peters의 제안을 사용하는 것입니다.

아래에 작은 C# 코드 샘플을 포함 시켰습니다.

var keyPair = GetKeypair();

PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);                        
byte[] serializedKey = privateKeyInfo.ToAsn1Object().GetDerEncoded();

AsymmetricKeyParameter deserializedKey1 = PrivateKeyFactory.CreateKey(serializedKey);
Assert.AreEqual(keyPair.Private, deserializedKey1);

AsymmetricKeyParameter deserializedKey2 = PrivateKeyFactory.CreateKey(privateKeyInfo);            
Assert.AreEqual(keyPair.Private, deserializedKey2);

샘플은 탄력성 성 API를 사용합니다. 메모 샘플이 키를 암호화하지 않습니다. 그만큼 CreatePrivateKeyInfo 키를 보호하기 위해 비밀번호를 사용할 수 있도록 메소드가 과부하됩니다.

질문의 두 번째 부분과 관련하여 키를 저장하는 데 사용해야하는 데이터 유형은 Varbinary (256)입니다.

질문의 첫 번째 부분으로 돌아가서 실제로 SQL Server가 암호화를 처리 할 수있는 옵션이 있습니다. 물론, 당신이 이것을하고 싶은지 여부는 당신의 응용 프로그램 요구 사항이 무엇인지에 대한 문제가 될 것입니다. 그러나 옵션 인 경우에 따라 갈 것입니다.

우리는 여기에서 매우 기본적이며 대칭 키와 트리플 데스를 사용합니다.

먼저, 데이터베이스에는 인증서와 비대칭 키를 보호하는 데 사용되는 마스터 키가 있습니다. 마스터 키는 트리플 데스로 암호화됩니다.

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'supersecretpassword'  

SQL Server 2005/2008은 실제 데이터를 암호화하는 데 사용되는 키를 보호하는 데 사용되는 자체 X.509 인증서를 생성 할 수 있습니다.

CREATE CERTIFICATE ExampleCertificate 
     WITH SUBJECT = 'thisisjustsomemetadata'

대칭 키 (인증서, 암호, 기타 키) 및 지원되는 많은 알고리즘을 암호화하기위한 많은 옵션이 있습니다. 그러나이 예에서는 인증서를 사용하겠습니다.

CREATE SYMMETRIC KEY ExampleKey
     WITH ALGORITHM = TRIPLE_DES  
     ENCRYPTION BY CERTIFICATE EncryptTestCert 

키는 암호화 된 것과 동일한 방법을 사용하여 해독해야합니다. 우리의 경우 이것은 우리가 만든 인증서입니다.

 DECLARE @Value VARCHAR(50)
 SET @Value = 'supersecretdata!'

 OPEN SYMMETRIC KEY ExampleKey DECRYPTION BY CERTIFICATE ExampleCertificate  
     UPDATE SomeTable  
     SET SomeColumn = ENCRYPTBYKEY(KEY_GUID('ExampleKey'), @Value)

암호 해독은 간단합니다.

OPEN SYMMETRIC KEY ExampleKey DECRYPTION BY CERTIFICATE ExampleCertificate  
     SELECT CONVERT(VARCHAR(50),DECRYPTBYKEY(SomeColumn)) AS DecryptedData 
     FROM SomeTable 

이로 인해 문제가 해결되거나 최소한 대체 솔루션을 열었습니다 (C# 앱에서 암호화를 경험 한 사람은 위의 코드에서 결함을 찾을 수 있지만). 데이터가 일반 텍스트로 SQL Server로 전선을 넘을 수 없어야하는 요구 사항이있는 경우, 이것은 분명히 중요하지 않습니다 (음, 여러분 ~할 수 있다 실제로 SQL Server에 대한 SSL 연결을 만듭니다 ...).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top