Closed malickf closed 7 years ago
Can you provide a complete example? You know, something with a main
that I can run?
Shooting from the hip, it seems like a good topic for documentation in the wiki.
We added additional Integer constructors intended to help with the little-endian byte array. See integer.h
: 145. Also see Integer on the Crypto++ wiki.
Thanks for your answer and details about integers. See below a more advanced example. I included the windows api in headers in order to be able to cast the blob to its corresponding structure .
I think that using the msdn documentation it should be possible to create a real import/export class or function for blobs.
Full example :
In c# to get blob and signature in 64 bit encoded string :
using System;
using System.Security.Cryptography;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var messageToSign = "hello";
RSAParameters privateKeyInfo;
RSAParameters publicKeyInfo;
CspParameters parameters = new CspParameters();
parameters.KeyNumber = (int)KeyNumber.Signature;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024, parameters))
{
rsa.PersistKeyInCsp = false;
privateKeyInfo = rsa.ExportParameters(true);
publicKeyInfo = rsa.ExportParameters(false);
}
var bytes = System.Text.Encoding.UTF8.GetBytes(messageToSign);
byte[] signedHash;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
// Import the key information.
rsa.ImportParameters(privateKeyInfo);
var cspBlob = rsa.ExportCspBlob(false); // false -> export only public key
// [A] export the key as a window blob 64 bit encoded string
var cspBlobBase64Signature = Convert.ToBase64String(cspBlob);
Console.WriteLine(String.Format("CSP Blob : {0} ", cspBlobBase64Signature));
// Sign the data, using SHA512 as the hashing algorithm
signedHash = rsa.SignData(bytes, CryptoConfig.MapNameToOID("SHA512"));
//[B] export the signed hash as a 64 bit encoded string
var signatureBase64Signature = Convert.ToBase64String(signedHash);
Console.WriteLine(String.Format("Signature : {1} ", signatureBase64Signature));
}
}
}
}
C++ :
#include "stdafx.h"
//cryptopp
#include "md5.h"
#include <cryptlib.h>
#include <sha.h>
#include <filters.h>
#include <rsa.h>
#include <files.h>
#include <base64.h>
#include <osrng.h>
//windowsAPI
#include "windows.h"
#include "minwindef.h"
#include "Wincrypt.h"
using CryptoPP::Integer;
using CryptoPP::StringSource;
using CryptoPP::Base64Decoder;
using namespace std;
using std::vector;
#pragma comment(lib, "cryptlibmtd")
bool Get_rsa_publicKey_from_windows_blob(std::string public_key_blob_64_bit_encoded, CryptoPP::RSA::PublicKey &publickey);
int main()
{
string message = "hello";
std::string public_key_blob_64_bit_encoded = "BgIAAACkAABSU0ExAAQAAAEAAQBNvUNW8njYzN8gMEIBJUnK9DczJ9ScEza/gehdIGhNVOUVE3iG8c5vO7zKhcFLthev0ysqMW/E10STW+YLDyfkHMWHy1Ai6AvvjY0zhluePzwPhXp2jXwxPCbkxdTjP2p/ngWBOs/PjJPP1MbARYMpjAajTlQT/k3cKcGN6bwRwA==";
std::string signature_64bit = "P3Uw36KgQ7ucngODaxoA2EG2qAR1qbwmlYGFLcMVCCvwBzNUQzTh6Pxa1FKhLeqoFn3siFGIfdus9Av5H5Pbe4gxllts/kIEmhVpUr1kGqfNX/x1AeCKUw+aZQaSunUEiUHTLvd7LufkkcGPTGJhHdo2M9J02bzBNsKKqQBFJ4w=";
CryptoPP::RSA::PublicKey publicKey;
if(!Get_rsa_publicKey_from_windows_blob(public_key_blob_64_bit_encoded, publicKey))
{
cout << "failure to get public key from blob ... " << endl;
return -1;
}
// decode signature to std::string
string decoded_signature;
Base64Decoder decoder;
decoder.Put( (byte*)signature_64bit.data(), signature_64bit.size() );
decoder.MessageEnd();
CryptoPP::word64 size = decoder.MaxRetrievable();
decoded_signature.resize(size);
decoder.Get((byte*)decoded_signature.data(), decoded_signature.size());
CryptoPP::RSASS<CryptoPP::PKCS1v15, CryptoPP::SHA512>::Verifier verif(publicKey);
bool res = verif.VerifyMessage( reinterpret_cast<const byte*>(message.c_str()), message.length(), reinterpret_cast<const byte*>(decoded_signature.c_str()), decoded_signature.length() );
if(res)
cout << "OK Message verified " <<endl;
else
cout << " Bad signature " <<endl;
return 0;
}
bool Get_rsa_publicKey_from_windows_blob(std::string public_key_blob_64_bit_encoded, CryptoPP::RSA::PublicKey &publickey)
{
// Decode public blob and convert it to vector<byte>
StringSource blob64(public_key_blob_64_bit_encoded, true, new Base64Decoder());
Integer blob_integer(blob64, blob64.MaxRetrievable());
size_t sz = blob_integer.MinEncodedSize();
vector<byte> vector_blob;
vector_blob.resize(sz);
blob_integer.Encode(&vector_blob[0], vector_blob.size());
PUBLICKEYSTRUC* ptr_pubkeustruc ;
RSAPUBKEY * ptr_RSAPUBKEY;
ptr_pubkeustruc = reinterpret_cast<PUBLICKEYSTRUC*>(&vector_blob[0]);
BYTE bType = ptr_pubkeustruc->bType;
if (bType != PUBLICKEYBLOB)
{
cout << "Invalid Blob - not a public blob " << endl;
return false;
}
ALG_ID alg = ptr_pubkeustruc->aiKeyAlg;
if (alg == CALG_RSA_KEYX) // "RSA public key exchange algorithm "
{
ptr_RSAPUBKEY = reinterpret_cast<RSAPUBKEY*>(&vector_blob[sizeof(PUBLICKEYSTRUC)]);
DWORD bitlen = ptr_RSAPUBKEY->bitlen;
DWORD pubexp = ptr_RSAPUBKEY->pubexp;
byte* exp = reinterpret_cast<byte*>(&pubexp);
if(bitlen != 1024)
{
cout << "Not 1024 rsa key ... " << endl;
return false;
}
BYTE* modulus = &vector_blob[sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)];// not sure if problem of paddings can occurs here ...
Integer pub(exp,4,Integer::UNSIGNED,CryptoPP::LITTLE_ENDIAN_ORDER);
Integer mod(modulus,128,Integer::UNSIGNED,CryptoPP::LITTLE_ENDIAN_ORDER);
CryptoPP::InvertibleRSAFunction params;
params.SetModulus(mod);
params.SetPublicExponent(pub);
CryptoPP::RSA::PublicKey pK(params);
CryptoPP::AutoSeededRandomPool rnd;
if(!pK.Validate(rnd, 3))
{
std::cout << "Invalid pubkey " << std::endl;
return false;
}
publickey = pK;
return true;
}
return false;
}
@malickf,
What do you suggest we do? Do you have specific actionable items?
I think the choices are:
I have some code that provides access to Windows DPAPI. It seemed too specialized for Crypto++, so I took the course of (4) and added it as a patch. You can find it at Protected Storage Pack.
@noloader I had some difficulties to interop with the windows API and cryptopp, even-those I finally succeed, mainly because I couldn't find a place summarizing info related to windows . I believe that the 3rd option (wiki page) could be a nice choice. Especially, it could be valuable to get a page that present briefly the different ways a user can take to initialize public/private key ( from raw values (exponent=....., modulus.... obtained via the FromXmlString() ) , from a blob, the preferable format/certificate to use to export/import keys ... etc dedicated to windows.
A "quick start guide for interop with Windows API" in short. With some specific informations (such as the PKCS1_v1.5 signature is required for RSA signature, maybe some compilation specific remarks, a remark about little-endian ...).
Also all cryptopp resources related to windows could be listed, such as your protected Storage Pack.
Thanks
Closing. I'll add a wiki page if I have some time.
I have a suggestion, I think it could be very nice to ease interop with the windows API.
This API has a windows blob key structure, that I believe could be used to instantiate cryptopp keys. Conversely, I think it could be nice to be able to export keys as windows blob.
This will also ease interop with the c# world as it is based on this API.
I do not know enough cryptopp and cryptography to do it myself, it is just a suggestion. In any cases, thanks A LOT for maintaining and developing this libray.
A pseudo example of what I'm thinking for the public blob key (blob encoded as a 64bit string but we could let the raw blob) for RSA digital signature :
Edit : based on this structure :
with :
see :