I have to write a program to establish a secure communication with a USB device. I have to use the private key generated from it which is stored in PKCS#1 format. As I have used Crypto++ in order part of my program, I would like to utilize it for this purpose as well.
However, I cannot find a way to import RSA private key from memory. It accepts private key in PKCS#8 format only. Could some pro show me a sample code on how to do it? Many thanks!
PKCS#1 format is ASN.1 encoded. For RSAPublicKey and RSAPrivateKey, its as easy as:
RSA::PublicKey publicKey(...);
ByteQueue queue;
publicKey.Save(queue);
// The public key is now in the ByteQueue in PKCS #1 format
// ------------
// Load a PKCS #1 private key
byte key[] = {...}
ArraySource arr(key, sizeof(key));
RSA::PrivateKey privateKey;
privateKey.Load(arr);
// The private key is now ready to use
Saving and loading keys is discussed in more detail at the Crypto++ wiki under Keys and Formats.
Related
I'm try to generate key pairs with CryptoKit, but seems like the key pairs is not compatible with other platform like https://8gwifi.org/ecsignverify.jsp
import CryptoKit
...
let privateKey = P256.Signing.PrivateKey()
let publicKey = privateKey.publicKey
//using this send this string to other platform
let publicKeyPem = publicKey.pemRepresentation
//keeping this one on my keychain
let privateKeyPem = privateKey.pemRepresentation
but this keypairs can't be verified in other platform, like when I sign some data with private key and can't be verified by someoneelse(but it works well on iOS platform, is there something I missed?)
You are using two different Curves. The link you specified shows that you are trying to initiate a secp256k1 key, but that is not the same as CryptoKit P256 - which is the Curve secp256r1, notice last two chara k1 != r1. Even if private key instantiation succeeds, the public keys will differ, so signature validation (verification) will always fail.
Can you use secp256r1? It is present in the list on the site you linked to, above sect571r1.
Do you have to use secp256k1? If so you can use
https://github.com/Sajjon/K1
Want to use secp256k1 in CryptoKit in the future? Help me upvote my proposal to get it added to swift-crypto (open source variant of CryptoKit)!
Im trying to use the SecKeyCopyKeyExchangeResult function to obtain the shared secret from my local private key and received public key of server.
Shared key is generated successfully and I able to decrypt incomming message with AES encryption
Not so long time ago server devs decided to add KDF to key generation flow.
I started investigate how I can do it on iOS side and find out that there is a special param static let sharedInfo: SecKeyKeyExchangeParameter
To say that documentation is poor its to say nothing...
Only what I did found is this description in header
#constant kSecKeyKeyExchangeParameterSharedInfo Contains CFDataRef
with additional shared info
for KDF (key derivation function).
If somebody have worked with this please help. Server use this params to generate KDF on scala
private def concatWithKdf(secretKey: SecretKey) = {
val bytes = new Array[Byte](SECRET_KEY_LENGTH)
val digest = new SHA256Digest();
val kdf1BytesGenerator = new KDF1BytesGenerator(digest)
kdf1BytesGenerator.init(new KDFParameters(secretKey.getEncoded, null))
kdf1BytesGenerator.generateBytes(bytes, 0, bytes.length)
new SecretKeySpec(bytes, secretKey.getAlgorithm)
}
Code on iOS side
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandard,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
You are totally right my friend, the documentation around the Security Framework is abysmal.
Indeed CryptoKit is Apple's attempt to modernise things here in a libsodium style providing simple interfaces to carefully selected primitives, such as elliptic curve Diffie-Hellman over safe curves.
So I sympathise, and suggest generally just use libsodium when you need crypto on iOS/macOS.
Anyway, to hopefully answer your question, I found a mention in the SecKit lib that matches what you seem to use in Scala, after the Diffie-Hellman process you are running the key material through SHA256 on the server side, so iOS needs to match this HBKDF.
#constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256
Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys
and apply ANSI X9.63 KDF with SHA256 as hashing function. Requires kSecKeyKeyExchangeParameterRequestedSize and allows
kSecKeyKeyExchangeParameterSharedInfo parameters to be used.
so I think you just need to change this:
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandard,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
to this:
var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
let secret = SecKeyCopyKeyExchangeResult(privateOwn,
SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256,
publicTheir,
dict as CFDictionary,
&keyExchangeError)
I haven't tested the above as I'm on a Linux machine atm, but hopefully it helps, it should add SHA256 based KDF onto the ECDH process. But yeah, what a mess of an API. I just can't work with it.
How to prove that certain data is calculated(or generated) inside Enclave(Intel SGX)?
I tried to generate asymmetric key pair inside enclave(private key might be invisible to outside), and
then expose public key with evidence(i guess quote or remote attestation related things).
I got how remote attestation goes but, i cannot come up with applying remote attestation to verifying enclave-generated data.
Is this possible scenario with Intel SGX?
You can prove the origin of the public key by placing it in the report_data field of a Quote generated during report attestation.
_quote_t.report_data can be used to attest arbitrary data:
The 64 byte data buffer is free form data and you can supply any information in that buffer that you would like to have identified as being in the possession and protection envelope of the enclave when the report/quote was generated. You can thus use this buffer to convey whatever information you would like to a verifying party. (Source)
The report_data field can be found by tracking the following structures:
sgx_key_exchange.h
typedef struct _ra_msg3_t {
sgx_mac_t mac
sgx_ec256_public_t g_a;
sgx_ps_sec_prop_desc_t ps_sec_prop;
uint8_t quote[]; // <- Here!
} sgx_ra_msg3_t;
sgx_quote.h
typedef struct _quote_t
{
uint16_t version;
uint16_t sign_type;
sgx_epid_group_id_t epid_group_id;
sgx_isv_svn_t qe_svn;
sgx_isv_svn_t pce_svn;
uint32_t xeid;
sgx_basename_t basename;
sgx_report_body_t report_body; // <- Here!
uint32_t signature_len;
uint8_t signature[];
} sgx_quote_t;
The Quote is part of the Msg3 (client-to-server) of remote attestation protocol. You can review the details of Msg3 creation in this official Code Sample and in the intel/sgx-ra-sample RA example.
In the latter, you can find out how the report is generated using sgx_create_report:
sgx_status_t get_report(sgx_report_t *report, sgx_target_info_t *target_info)
{
#ifdef SGX_HW_SIM
return sgx_create_report(NULL, NULL, report);
#else
return sgx_create_report(target_info, NULL, report);
#endif
}
In both cases, second argument sgx_report_data_t *report_data is NULL and can be replaced by pointer to arbitrary input. This is where you want to put your public key or any other data.
I am supplied the following RSA private key in the format
<RSAKeyValue>
<Modulus>XXXXXXXX</Modulus>
<Exponent>XXXXXXXX</Exponent>
<P>XXXXXXXX</P>
<Q>XXXXXXXX</Q>
<DP>XXXXXXXX</DP>
<DQ>XXXXXXXX</DQ>
<InverseQ>XXXXXXXXXX/InverseQ>
<D>XXXXXXXX</D>
</RSAKeyValue>
The XXXX are in Base64 format.
I want to know how to combine it all the XXXXXX bits to a single Base64 string.
With this single Base64 string i do the following:
1. Feed it to a TMemorStream
2. use Indy's TIdDecoderMIME class to decode Base64 from the MemoryStream
3. The decoded MemoryStream is then feed into CryptDecrypt function from wcrypt2.pas (a delphi wrapper of Microsoft's Cryptographic API) from Jedi
I know the solution for public key in the same format
<RSAKeyValue>
<Modulus>xqiYKv0umaLdmrKPyBfYmAfzZYVsvsOJyS4c1lBPjqpn7zh+XyxPXK7MxJkAlenQJM33M+ZYfmlPLya7JWXXTPviylEEtlmul9GshpX2caxWu2YO9vNIHRZYYau4ccbkm95iMyJi8KN2ANtqDwiJv55vcXZDqjPSDE4ap49xmog==</Modulus>
<Exponent>AAQC</Exponent>
</RSAKeyValue>
The solution is to add "BgIAAACkAABSU0ExAAQAAAE" + Exponent + Modulus
The result is:
BgIAAACkAABSU0ExAAQAAAEAAQCxqiYKv0umaLdmrKPyBfYmAfzZYVsvsOJyS4c1lBPjqpn7zh+XyxPXK7MxJkAlenQJM33M+ZYfmlPLya7JWXXTPviylEEtlmul9GshpX2caxWu2YO9vNIHRZYYau4ccbkm95iMyJi8KN2ANtqDwiJv55vcXZDqjPSDE4ap49xmog==
With the private key how do we combine it? I know it starts off like this:
"BwIAAACkAABSU0ExAAQAAAE" + Exponent + Modulus + ???????
The XXXX in the RSAKeyValue XML are in base64, just that i do not want to expose the details there. I want to know how do i combine all the XXXX base64 codes into a single base64 private key.
I suspect that this means that you are performing the base64 encoding line by line. It's much simpler to perform the encoding on the entire file.
For example you might do this as follows:
Load the file into a TStringList.
Extract a single string representing the file using the Text property of the string list.
Base64 encode that string.
Send it over the wire.
At the receiving end, decode the string.
Assign the string to the Text property of a string list.
I have generated a pair of private/public keys and I have managed to load the private key to sign some bytes. The problem ocurrs when I try to load the public key from memory to verify the signature.
Here is some code :
privateKey := BIO_new(BIO_s_mem);
PEM_write_bio_RSAPrivateKey(privateKey,rsa,enc,nil,0,nil,PChar('1234567890'));
publicKey := BIO_new(BIO_s_mem);
PEM_write_bio_RSAPublicKey(publicKey,rsa);
WriteLn(GetErrorMessage);
//No error so far
Writeln('Keys generated!');
pKey := nil;
PEM_read_bio_PrivateKey(privateKey,pKey,nil,PChar('1234567890'));
// pKey is ok
mKey := nil;
PEM_read_bio_PUBKEY(publicKey,mKey,nil,nil);
WriteLn(GetErrorMessage);
The error message output by the last line is
PEM routines : PEM_read_bio : no start line
What am I doing wrong ?
The problem is that you're mixing PEM_write_bio_RSAPublicKey() and PEM_read_bio_PUBKEY(). The former writes a PKCS#1 RSAPublicKey structure, while the latter expects a SubjectPublicKeyInfo structure. The two structures are not interchangeable, hence your error upon read.
To resolve this error, use PEM_write_bio_RSA_PUBKEY() when writing your public key to BIO.