2015-03-14 30 views
5

Ist es möglich, eine RSA Private/Public Key in der Quelle zum Beispiel zur Speicherung in einem byte[] oder string oder anderen container und nutzen diese eine Private/Public Key aus einem String/Byte-Array oder einem anderen Container laden Schlüssel für die Verschlüsselung/Entschlüsselung?Wie würde ich

Eine Dekodierungsfunktion aus der Datei würde wie folgt aussehen:

void Decode(const string& filename, BufferedTransformation& bt) 
{ 
    // http://www.cryptopp.com/docs/ref/class_file_source.html 
    FileSource file(filename.c_str(), true /*pumpAll*/); 

    file.TransferTo(bt); 
    bt.MessageEnd(); 
} 

, dass der Schlüssel aus einer Datei lädt, die nicht das, was ich will.

Ich weiß, dass es möglich sein muss, da ich den Schlüssel mit AutoSeededRandomPool erstellen kann.

Ich weiß einfach nicht, wie man ein vorhandenes verwendet.

Vielleicht übersehen ich diesen Teil in der Dokumentation.

+0

Eigentlich Ich frage mich nur, ob das Problem eine geeignete Quelle/Senke ist (zB 'ArraySink' /' ArraySource' anstelle von 'FileSource' /' FileSink'), nicht die Kodierung/Dekodierung des Schlüsselmaterials wie ich antwortete. Könntest Du das erläutern? – softwariness

+0

@softwariness Ihre Antwort ist wirklich gut, aber ja, es ist mehr über die Wahl einer geeigneten Quelle/Senke: D Ich wusste nicht über ArraySink obwohl O.o, die helfen könnte. Wenn Sie in Ihrer Antwort auch etwas zu den Senken hinzufügen können, akzeptiere ich es. – deW1

+0

Antwort jetzt aktualisiert mit einem Beispiel, das Rundauslösungs-Schlüsselmaterial durch einen Speicherpuffer zeigt, und ein anderes zeigt das Schlüsselmaterial, das in einer std :: string gespeichert ist mit StringSink/StringSource, die einen Teil der Pufferverwaltung vermeidet. – softwariness

Antwort

9

Die Seiten Crypto++ Keys and Formats und Crypto++ RSA Cryptography könnten von Interesse sein.

Wenn Sie die RSA-Parameter, wie das hier zu erzeugen:

AutoSeededRandomPool rng; 

InvertibleRSAFunction params; 
params.GenerateRandomWithKeySize(rng, 2048); 

Sie die Verwendung der DEREncode und BERDecode Methoden der InvertibleRSAFunction können alle Parameter zu kodieren und dekodieren jeweils:

{ 
    FileSink output("rsaparams.dat"); 
    params.DEREncode(output); 
} 

InvertibleRSAFunction params2; 
{ 
    FileSource input("rsaparams.dat", true); 
    params2.BERDecode(input); 
} 

Verwenden Sie die DEREncode und BERDecode Methoden auf dem RSA::PrivateKey und, um das private und öffentliche Material separat zu codieren/decodierenObjekte selbst:

// Initialize keys from generated params 
RSA::PrivateKey rsaPrivate(params); 
RSA::PublicKey rsaPublic(params); 

// Write keys to file 
{ 
    FileSink output("rsaprivate.dat"); 
    rsaPrivate.DEREncode(output); 
} 
{ 
    FileSink output("rsapublic.dat"); 
    rsaPublic.DEREncode(output); 
} 

// Read keys from file into new objects 
RSA::PrivateKey rsaPrivate2; 
RSA::PublicKey rsaPublic2; 
{ 
    FileSource input("rsaprivate.dat", true); 
    rsaPrivate2.BERDecode(input); 
} 
{ 
    FileSource input("rsapublic.dat", true); 
    rsaPublic2.BERDecode(input); 
} 

FileSource und FileSink sind nur Beispiel Quelle und Senke Objekte, die Sie nutzen könnten. Die Codierungs-/Decodierroutinen nehmen BufferedTransformation Objekte als Parameter, so dass Sie andere geeignete Implementierungen dieser Schnittstelle verwenden können.

Zum Beispiel kann ArraySink verwendet werden, um Daten in einen Speicherpuffer zu schreiben, den Sie liefern, und StringSource (also aliased as ArraySource) kann verwendet werden, um aus einem Puffer zu lesen.

Hier einige Code Verwendung von ArraySink und ArraySource zu Round-Trip mit dem privaten Schlüssel Material durch eine std::vector<byte> zeigt:

RSA::PrivateKey rsaPrivate(params); 
std::vector<byte> buffer(8192 /* buffer size */); 

ArraySink arraySink(&buffer[0], buffer.size()); 
rsaPrivate.DEREncode(arraySink); 

// Initialize variable with the encoded key material 
// (excluding unwritten bytes at the end of our buffer object) 
std::vector<byte> rsaPrivateMaterial(
    &buffer[0], 
    &buffer[0] + arraySink.TotalPutLength()); 

RSA::PrivateKey rsaPrivate2; 
ArraySource arraySource(
    &rsaPrivateMaterial[0], 
    rsaPrivateMaterial.size(), 
    true); 
rsaPrivate2.BERDecode(arraySource); 

(Siehe auch @jww's answer für ein Beispiel, das durch die Verwendung eines ByteQueue die Puffer fester Größe vermeidet).

Und ein weiteres Beispiel eines std::string mit dem Schlüsselmaterial zu speichern und mit der StringSink Klasse zu schreiben, die einen Teil der Pufferverwaltung vermeidet (die Zeichenfolge automatisch die Datenmenge entsprechen der Größe verändert werden, die codiert wird). Beachten Sie, dass dies immer noch Binärdaten sind, obwohl es sich in einem std::string Objekt befindet.

RSA::PrivateKey rsaPrivate(params); 

std::string rsaPrivateMaterial; 
StringSink stringSink(rsaPrivateMaterial); 
rsaPrivate.DEREncode(stringSink); 

RSA::PrivateKey rsaPrivate2; 
StringSource stringSource(rsaPrivateMaterial, true); 
rsaPrivate2.BERDecode(stringSource); 

Alternativ, wenn Sie das Format selbst steuern möchten, können Sie die Methoden des InvertibleRSAFunction Objekt oder die Schlüsselobjekte verwenden, um die einzelnen Parameter zu extrahieren (wie in der „Crypto ++ RSA Cryptography“ Link oben) und verwenden, dass die Werte für die Speicherung in Ihrem eigenen Format zu extrahieren:

const Integer& n = params.GetModulus(); 
const Integer& p = params.GetPrime1(); 
const Integer& q = params.GetPrime2(); 
const Integer& d = params.GetPrivateExponent(); 
const Integer& e = params.GetPublicExponent(); 

Diese werden dann zu einer neuen InvertibleRSAFunction oder RSA::*Key Instanz gestellt werden können, wenn aus der Datei oder Containern lesen, indem Sie die entsprechenden Setter-Methoden unter Verwendung von (SetModulus(), SetPrime1() , etc.).

3

Wie würde ich eine Private/Public Key aus einem String/Byte-Array laden oder andere Behälter

Die Bibliothek ++ Crypto hat eine integrierte Unterstützung für std:strings. Aber andere C++ Container werden kniffliger. ArraySource wurde bei Crypto ++ 5.6 hinzugefügt, aber es ist nur ein typedef für StringSource. Wenn Sie empfindliches Material verwenden, sollten Sie auch eine SecByteBlock in Betracht ziehen. Wenn der Destruktor ausgeführt wird, wird das empfindliche Material gelöscht oder zurückgesetzt.

String und StringSource (load)

string spki = ...; 
StringSource ss(spki, true /*pumpAll*/); 

RSA::PublicKey publicKey; 
publicKey.Load(ss); 

Vektor und ArraySource (Last)

vector<byte> spki = ...; 
ArraySource as(&spki[0], spki.length(), true /*pumpAll*/); 

RSA::PublicKey publicKey; 
publicKey.Load(as); 

String und StringSink (save)

string spki; 
StringSink ss(spki); 

RSA::PublicKey publicKey(...); 
publicKey.Save(ss); 

Vektor (speichern)

Siehe Code unten.


Unten ist ein Beispiel zu und Laden von einem std::vector zu retten. Sie müssen ein Zwischenprodukt ByteQueue verwenden, um zu speichern, weil Sie nicht einfach ein VectorSink erstellen können.

AutoSeededRandomPool prng; 
RSA::PrivateKey pk1, pk2; 

pk1.Initialize(prng, 1024); 
ByteQueue queue; 
pk1.Save(queue); 

vector<byte> spki; 
spki.resize(queue.MaxRetrievable()); 

ArraySink as1(&spki[0], spki.size()); 
queue.CopyTo(as1); 

ArraySource as2(&spki[0], spki.size(), true); 
pk2.Load(as2); 

bool valid = pk2.Validate(prng, 3); 
if(valid) 
    cout << "Validated private key" << endl; 
else 
    cout << "Failed to validate private key" << endl; 

Wir haben keine explizite VectorSink, und wir können aufgrund einer impliziten Erwartung traits_type::char_type nicht leicht erstellen. Zum Beispiel:

using CryptoPP::StringSinkTemplate; 
typedef StringSinkTemplate< std::vector<byte> > VectorSink; 

In file included from cryptopp-test.cpp:65: 
In file included from /usr/local/include/cryptopp/files.h:5: 
/usr/local/include/cryptopp/filters.h:590:22: error: no member named 
     'traits_type' in 'std::vector<unsigned char, std::allocator<unsigned char> 
     >' 
     typedef typename T::traits_type::char_type char_type; 
         ~~~^ 
cryptopp-test.cpp:243:20: note: in instantiation of template class 
     'CryptoPP::StringSinkTemplate<std::vector<unsigned char, 
     std::allocator<unsigned char> > >' requested here 
     VectorSink vs(spki); 

können Sie erstellen die VectorSource und VectorSink, seine gerade dabei einige Arbeit. Sie können sich eine Vorstellung von der Arbeit machen, indem Sie sich StringSource und StringSink Quellcode in filters.h und filters.cpp ansehen.

+0

sollte diese Zeile nicht 'publicKey.Save (ss);' statt 'publicKey.Save (spki);' seit 'Save()' dauert a gepufferte Transformation? – deW1

+0

das gleiche gilt für Load() – deW1

+0

@ deW1 - Ja, aufgeräumt. Danke (und tut mir leid). – jww

0

Wenn Sie DSA-Schlüssel wie folgt erstellen, erhalten Sie zwei Dateien, eine mit dem privaten Schlüssel und die andere mit dem öffentlichen Schlüssel.

void CreateDsaKeys(std::string folder) 
{ 
    AutoSeededRandomPool rng; 
    // Generate Private Key 
    DSA::PrivateKey privateKey; 
    privateKey.GenerateRandomWithKeySize(rng, 1024); 

    // Generate Public Key 
    DSA::PublicKey publicKey; 
    publicKey.AssignFrom(privateKey); 
    if (!privateKey.Validate(rng, 3) || !publicKey.Validate(rng, 3)) 
    { 
     throw runtime_error("DSA key generation failed"); 
    } 
    std::string publicPath = folder + "/publickey.txt"; 
    std::string privatePath = folder + "/privatekey.txt"; 
    SaveHexPublicKey(publicPath, publicKey); 
    SaveHexPrivateKey(privatePath, privateKey); 
} 

kopieren Sie den Inhalt dieser beiden Dateien in den Quelltext und in Strings setzen:

std :: string publickey ("308201B73082012C ... F752BB791");

std :: String privater Schlüssel ("3082014C0201003 ... 0B8E805D83E9708");

Dann können Sie HexDecoder verwenden, um die Strings in Bytes zu konvertieren und die öffentlichen und privaten Schlüssel erstellen, um diese Bytes mit:

bool LoadDsaKeysFromStringsAndTest() 
{ 
    AutoSeededRandomPool rng; 
    HexDecoder decoderPublic; 
    decoderPublic.Put((byte*)publickey.data(), publickey.size()); 
    decoderPublic.MessageEnd(); 
    HexDecoder decoderPrivate; 
    decoderPrivate.Put((byte*)privatekey.data(), privatekey.size()); 
    decoderPrivate.MessageEnd(); 
    DSA::PublicKey publicKey; 
    publicKey.Load(decoderPublic); 
    DSA::PrivateKey privateKey; 
    privateKey.Load(decoderPrivate); 
    string message = "DSA Signature"; 
    string signature; 
    try { 
     DSA::Signer signer(privateKey); 
     StringSource ss1(message, true, 
      new SignerFilter(rng, signer, 
       new StringSink(signature) 
      ) // SignerFilter 
     ); // StringSource 

     bool result = false; 
     DSA::Verifier verifier1(publicKey); 
     StringSource ss(message+signature, true, 
       new SignatureVerificationFilter(verifier1, 
         new ArraySink((uint8_t*)&result, sizeof(result)), 
         SignatureVerificationFilter::PUT_RESULT | SignatureVerificationFilter::SIGNATURE_AT_END) 
       ); 
     return result; 
    } 
    catch(const CryptoPP::Exception& e) 
    { 
     std::cerr << e.what() << std::endl; 
    } 
    return false; 
} 

Diese sind die anderen Routinen erforderlich, um die Tasten zu speichern

void Save(const string& filename, const BufferedTransformation& bt) 
{ 
    FileSink file(filename.c_str()); 
    bt.CopyTo(file); 
    file.MessageEnd(); 
} 

void SaveHex(const string& filename, const BufferedTransformation& bt) 
{ 
    HexEncoder encoder; 
    bt.CopyTo(encoder); 
    encoder.MessageEnd(); 
    Save(filename, encoder); 
} 

void SaveHexPrivateKey(const string& filename, const PrivateKey& key) 
{ 
    ByteQueue queue; 
    key.Save(queue); 
    SaveHex(filename, queue); 
} 

void SaveHexPublicKey(const string& filename, const PublicKey& key) 
{ 
    ByteQueue queue; 
    key.Save(queue); 
    SaveHex(filename, queue); 
}