Related
I am using OPTEE-OS and mbedTLS and want to create a CSR. I am creating my EC key using the Global Platform API:
res = TEE_AllocateTransientObject(
TEE_TYPE_ECDSA_KEYPAIR,
DSEC_ECDSA_SHA256_KEY_BITS,
&key_pair);
if (res != TEE_SUCCESS) {
return res;
}
Then extract the private key:
res = TEE_GetObjectBufferAttribute(
key_pair,
TEE_ATTR_ECC_PRIVATE_VALUE,
buffer,
&bufferlen);
if (res != TEE_SUCCESS) {
return res;
}
Then use mbedTLS to parse this value and create a to create a CSR:
mbedtls_pk_context priv_key;
mbedtls_pk_init(&priv_key);
ret = mbedtls_pk_parse_key(
&priv_key,
key,
size,
NULL ,
0
);
However, the extracted value from TEE_GetObjectBufferAttribute does not have the headers and footpage:
"-----BEGIN EC PRIVATE KEY-----"
"-----END EC PRIVATE KEY-----"
and is only a binary array (not a string). I am currently getting the following error code: "-15616: PK - Invalid key tag or value".
Is there any way to create a mbedtls_pk_context with only the binary value of my private key?
The parsing functions in Mbed TLS's pk.h expect DER or PEM input. If you can find ready-made code to export a key as DER (or PEM) from OPTEE, that'll be easier (but possibly marginally less efficient). On the other hand, it's easier to do the import manually than to write a DER export function.
You need to call mbedtls_pk_setup() to declare that the context will contain an ECC key, then build the ECC key directly using the interface in ecp.h. Convert the curve designation from the TEE encoding to the Mbed TLS encoding, and calculate the public key from the private value. (Alternatively, you could export TEE_ATTR_ECC_PUBLIC_VALUE and set ec->Q, but that's more work.)
mbedtls_ecp_grp_id grp_id = …; // you need to convert this from the `TEE_ATTR_ECC_CURVE`
mbedtls_pk_context pk;
mbedtls_ecp_keypair *ec = malloc(sizeof(mbedtls_ecp_keypair));
mbedtls_pk_init(&pk);
mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECDSA));
mbedtls_ecp_keypair_init(ec);
mbedtls_ecp_group_load(&ec->grp, grp_id);
mbedtls_mpi_read_binary(&ec->d, buffer, bufferlen);
mbedtls_ecp_check_privkey(&ec->grp, &ec->d);
mbedtls_ecp_mul(&ec->grp, &ec->Q, &ec->d, &ec->grp.G, mbedtls_ctr_drbg_random, &ctr_drbg);
pk->pk_ctx = ec;
Completely untested. Error checking omitted. ctr_drbg is a CTR_DRBG instance, used for blinding during the calculation of the public key.
To add to the accepted answer here is the code to import Q if there are X and Y available as buffers. And I guess those are available since in order to create an ECDSA key in OPTEE using GlobalPlatform crypto API all 4 attributes (TEE_ATTR_xxx) are required (d, Q(X,Y) and the curve id)
rc = mbedtls_mpi_read_binary(&ec->Q.X, buffer_x, buffer_x_size);
rc = mbedtls_mpi_read_binary(&ec->Q.Y, buffer_y, buffer_y_size);
rc = mbedtls_mpi_lset(&ec->Q.Z, 1);
rc = mbedtls_ecp_check_pubkey(&ec->grp, &ec->Q);
I have a certificate in pem format and I want to extract the public key (RSA). I'm already this far:
{ok, PemBin} = file:read_file("/path/to/certificate.pem").
[Certificate] = public_key:pem_decode(PemBin).
Now, I can do the following:
public_key:pem_entry_decode(Certificate).
This gives me a tuple with all sorts of details on the certificate but I can't see anywhere an entry for the public key. How do I get the public key from this certificate? Should be straight forward but I can't find any function in the public_key-module for that.
Ok, here is the complete function in a module:
-module(crypto_helper).
-include_lib("public_key/include/public_key.hrl").
-export([get_public_key_from_cert/1]).
get_public_key_from_cert(PathToCert) ->
{ok, PemBin} = file:read_file(PathToCert),
PemEntries = public_key:pem_decode(PemBin),
{value, CertEntry} = lists:keysearch(‘Certificate’, 1, PemEntries)
{_, DerCert, _} = CertEntry,
Decoded = public_key:pkix_decode_cert(DerCert, otp),
PublicKey = Decoded#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey,
PublicKey.
Now you can use it as follows:
PublicKey = crypto_helper:get_public_key_from_cert("/usr/admin/myServer/priv/certificate.pem"),
EncryptedMsg = public_key:encrypt_public(<<"Hallo">>, PublicKey),
public_key:pem_entry_decode(Certificate) returns a Certificate record. To extract the public key from it, you need to load the record definitions. In the Erlang shell, type the following:
rr(public_key).
After loading the record definitions into the shell, return values will contain the field names as well as the field values, which should make things a bit clearer.
In an Erlang module, load the header file like this:
-include_lib("public_key/include/public_key.hrl").
Then you can extract the public key info like this:
DecodedCertificate = public_key:pem_entry_decode(Certificate).
DecodedCertificate#'Certificate'.tbsCertificate#'TBSCertificate'.subjectPublicKeyInfo.
which returns:
#'SubjectPublicKeyInfo'{
algorithm =
#'AlgorithmIdentifier'{
algorithm = {1,2,840,113549,1,1,1},
parameters = <<5,0>>},
subjectPublicKey =
<<48,130,2,10,2,130,2,1,0,195,76,200,181,90,146,51,183,
39,91,176,28,95,117,241,28,140,...>>}
Or dig down one level further to get the key itself:
DecodedCertificate#'Certificate'.tbsCertificate
#'TBSCertificate'.subjectPublicKeyInfo
#'SubjectPublicKeyInfo'.subjectPublicKey.
<<48,130,2,10,2,130,2,1,0,195,76,200,181,90,146,51,183,39,
91,176,28,95,117,241,28,140,212,223,132,...>>
Hello I am writing oauth 2 library to access google api's and my code is as follows
jwt_create() ->
{ok,PemBin} = file:read_file("your-key-file.pem"),
PemEntry = public_key:pem_decode(PemBin),
[A,B] = PemEntry,
io:format("A:: ~p ~n",[A]),
PrivateKey = public_key:pem_entry_decode(PemEntry),
JwtHeaderJson = encode_json(jwt_header()),
JwtClaimsetJson = encode_json(jwt_claimset()),
ComputeSignature = compute_signature(JwtHeaderJson, JwtClaimsetJson, PrivateKey),
Z=binary:replace(
binary:replace(<<JwtHeaderJson/binary, ".", JwtClaimsetJson/binary, ".", ComputeSignature/binary>>,
<<"+">>, <<"-">>, [global]),
<<"/">>, <<"_">>, [global]),
io:format("JWT:: ~p ~n",[Z]).
compute_signature(Header, ClaimSet,#'RSAPrivateKey'{publicExponent=Exponent
,modulus=Modulus
,privateExponent=PrivateExponent}) ->
base64:encode(crypto:sign(rsa, sha256, <<Header/binary, ".", ClaimSet/binary>>,
[Exponent, Modulus, PrivateExponent])).
encode_json(JWToken) ->
base64:encode(jsx:encode(JWToken)).
I am getting error as follows:
exception error: no function clause matching
public_key:pem_entry_decode([{'PrivateKeyInfo',<<48,130,4,191,2,1,0,48,13,6,9,42,134,
72,134,247,13,1,1,1,5,0,4,130,4,...>>,
not_encrypted},
{'Certificate',<<48,130,3,96,48,130,2,72,160,3,2,1,2,2,8,
79,59,244,35,60,15,3,155,48,...>>,
not_encrypted}]) (public_key.erl, line 123)
in function googleoauth:jwt_create/0 (src/googleoauth.erl, line 55)
Please help me in generating JWS and JWT for OAUTH 2 for accessing google apis
You are passing the wrong thing to public_key:pem_entry_decode/1:
This will resolve your problem:
PrivateKey = public_key:pem_entry_decode(A),
public_key:pem_entry_decode/1 takes a single pem_entry() but a PEM file can contain many entries, perhaps your code PemEntry = public_key:pem_decode(PemBin) should read PemEntries = public_key:pem_decode(PemBin) instead?
Also note the line before assumes 2 list entries, you might have meant this instead (not sure your intent here though)?
[A|B] = PemEntry,
I need help with a code to convert an AnalogIn input on the mbed LPC1768 to digital to be used by the CAN controller.The example syntax I'm using is
if(can1.write(CANMessage(1337, &counter, 2))) {
..........
}
where "counter" is the data to be transmitted and defined by me as a signed int (the example however defines it as a char). But I keep getting an error message
Error: No instance of constructor "mbed::CANMessage::CANMessage" matches the argument list in "project_test.cpp"
The controller CANMessage syntax is
CANMessage(int _id, const char *_data, char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard) {
len = _len & 0xF;
type = _type;
format = _format;
id = _id;
memcpy(data, _data, _len);
}
I really do not understand the controller syntax and how to apply it. Any help in explaining would be appreciated. Thanks
Since CANMessage only accepts a char* for the data paramter, you can convert your signed int value (which is 4 bytes) to an unsigned char like this:
unsigned char buf[0x8];
buf[0]=value & 0x000000ff;
buf[1]=(value >> 8) & 0x000000ff;
buf[2]=(value >> 16) & 0x000000ff;
buf[3]=(value >> 24) & 0x000000ff;
and then
if (can1.write(CANMessage(1337, &buf, 8))) {
..........
}
I am tumbling around with CryptoPP and cannot find answer to this specific question. Here is sample source code (partial)
AutoSeededRandomPool prng;
//Generate a private key
ECDSA<ECP, CryptoPP::SHA256>::PrivateKey privateKey;
privateKey.Initialize(prng, CryptoPP::ASN1::secp256r1());
// Generate publicKey
ECDSA<ECP, CryptoPP::SHA256>::PublicKey publicKey;
privateKey.MakePublicKey(publicKey);
// Extract Component values
Integer p = privateKey.GetGroupParameters().GetCurve().GetField().GetModulus();
Integer a = privateKey.GetGroupParameters().GetCurve().GetA();
Integer b = privateKey.GetGroupParameters().GetCurve().GetB();
Integer Gx = privateKey.GetGroupParameters().GetSubgroupGenerator().x;
Integer Gy = privateKey.GetGroupParameters().GetSubgroupGenerator().y;
Integer n = privateKey.GetGroupParameters().GetSubgroupOrder();
Integer h = privateKey.GetGroupParameters().GetCofactor();
Integer Qx = publicKey.GetPublicElement().x;
Integer Qy = publicKey.GetPublicElement().y;
Integer x = privateKey.GetPrivateExponent();
// Construct Point elelemt;
ECP curve(p,a,b);
ECP::Point G(Gx,Gy);
ECP::Point Q(Qx,Qy);
//Build publicKey using elements (no point compression)
ECDSA<ECP, CryptoPP::SHA256>::PublicKey GeneratedPublicKey;
GeneratedPublicKey.Initialize(curve,G,n,Q);
assert(GeneratedPublicKey.Validate(prng, 3));
//Build publicKey using elements (with point compression)?
With this way, I can generate publicKey using component values. However, I cannot
make it work with point compression-which means I don't have Qy value- Is there a
way to do it? Initialize method has two overloading but none of them are for point
compression situation.
My question is specific with Crypto++ on "PublicKey.Initialize(curve,G,n,Q)". Since I cannot transfer whole publicKey with my current project-which I am force to specify domain
parameter as index value and can only transfer Qx value. So I should initialize publicKey
using something like "PublicKey.Initialize(curve,G,n,Q)" However, I cannot find such initialization API concerning point compression.
So, this is not about "how to do a point compression" but "Is there a way to initialize
public key without having Qy value?"
How to Construct ECDSA publicKey using only with x value (Point compression)?
x is the private exponent. The public key is a point on the curve; and it does not use the private exponent.
To get the public key: take the private exponent, and raise your base point to it. That is, Q = G^x.
If you want to set the private exponent on a private key or decryptor, then set the domain parameters (i.e., DL_GroupParameters_EC< ECP > or DL_GroupParameters_EC< EC2M >) and then call SetPrivateExponent(x);.
Have you reviewed your previous question at How can I recover compressed y value from sender?? The community took the time to provide you with an answer and sample code, but you did not acknowledge or follow up.
I think owlstead said it best here:
Why would we care answer you if you are not inclined to accept answers
or even follow up to them? Your questions are all right, but the way
you treat the community is terrible.
"Is there a way to initialize public key without having Qy value?"
Yes, there is. Here is an crypto++ example:
#include <string>
#include <iostream>
#include <cryptopp/cryptlib.h>
#include <cryptopp/ecp.h>
#include <cryptopp/eccrypto.h>
#include <cryptopp/hex.h>
#include <cryptopp/oids.h>
#include <cryptopp/osrng.h>
using namespace CryptoPP;
using std::cout;
using std::endl;
int main()
{
OID curve = ASN1::secp256r1();
ECDH<ECP>::Domain domain(curve);
SecByteBlock privKey(domain.PrivateKeyLength());
SecByteBlock pubKey(domain.PublicKeyLength());
AutoSeededRandomPool prng;
domain.GenerateKeyPair(prng, privKey, pubKey);
// Convert public key to string representation
std::string pub_str;
HexEncoder encoder;
encoder.Attach( new StringSink(pub_str) );
encoder.Put( pubKey.data(), pubKey.size() );
encoder.MessageEnd();
// Uncompressed point - first byte '04' in front of the string.
std::cout << "Uncompressed public key (point) " << pub_str << endl;
// Extract x value from the point
std::string public_point_x = pub_str.substr(2, 64);
// Compressed - '02' byte in front of the string.
public_point_x = "02" + public_point_x;
std::cout << "Compressed public key (point) " << public_point_x << endl;
// ----- reconstruct point from compressed point/value.
StringSource ss(public_point_x, true, new HexDecoder);
ECP::Point point;
domain.GetGroupParameters().GetCurve().DecodePoint(point, ss, ss.MaxRetrievable());
cout << "Result after decompression X: " << std::hex << point.x << endl;
cout << "Result after decompression Y: " << std::hex << point.y << endl;
return 0;
}
I hope this is the answer to your question. I was using ECDH, but it should work equally well with ECDSA class.