Parse a ECC private key buffer - mbedtls

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);

Related

Parse string into map Golang

I have a string like A=B&C=D&E=F, how to parse it into map in golang?
Here is example on Java, but I don't understand this split part
String text = "A=B&C=D&E=F";
Map<String, String> map = new LinkedHashMap<String, String>();
for(String keyValue : text.split(" *& *")) {
String[] pairs = keyValue.split(" *= *", 2);
map.put(pairs[0], pairs.length == 1 ? "" : pairs[1]);
}
Maybe what you really want is to parse an HTTP query string, and url.ParseQuery does that. (What it returns is, more precisely, a url.Values storing a []string for every key, since URLs sometimes have more than one value per key.) It does things like parse HTML escapes (%0A, etc.) that just splitting doesn't. You can find its implementation if you search in the source of url.go.
However, if you do really want to just split on & and = like that Java code did, there are Go analogues for all of the concepts and tools there:
map[string]string is Go's analog of Map<String, String>
strings.Split can split on & for you. SplitN limits the number of pieces split into like the two-argument version of split() in Java does. Note that there might only be one piece so you should check len(pieces) before trying to access pieces[1] say.
for _, piece := range pieces will iterate the pieces you split.
The Java code seems to rely on regexes to trim spaces. Go's Split doesn't use them, but strings.TrimSpace does something like what you want (specifically, strips all sorts of Unicode whitespace from both sides).
I'm leaving the actual implementation to you, but perhaps these pointers can get you started.
import ( "strings" )
var m map[string]string
var ss []string
s := "A=B&C=D&E=F"
ss = strings.Split(s, "&")
m = make(map[string]string)
for _, pair := range ss {
z := strings.Split(pair, "=")
m[z[0]] = z[1]
}
This will do what you want.
There is a very simple way provided by golang net/url package itself.
Change your string to make it a url with query params text := "method://abc.xyz/A=B&C=D&E=F";
Now just pass this string to Parse function provided by net/url.
import (
netURL "net/url"
)
u, err := netURL.Parse(textURL)
if err != nil {
log.Fatal(err)
}
Now u.Query() will return you a map containing your query params. This will also work for complex types.
Here is a demonstration of a couple of methods:
package main
import (
"fmt"
"net/url"
)
func main() {
{
q, e := url.ParseQuery("west=left&east=right")
if e != nil {
panic(e)
}
fmt.Println(q) // map[east:[right] west:[left]]
}
{
u := url.URL{RawQuery: "west=left&east=right"}
q := u.Query()
fmt.Println(q) // map[east:[right] west:[left]]
}
}
https://golang.org/pkg/net/url#ParseQuery
https://golang.org/pkg/net/url#URL.Query

(Erlang) extracting public key from certificate in pem format

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,...>>

Is there public key initialization API with point compression?

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.

OpenSSL Get Subject Alternative Name from certificate

I'm developing an iOS app that will need to read Subject Alternative Name from an certificate (.pfx).
Security.framework doesn't have a way to get this information, so you I'm using OpenSSL(openssl-1.0.1e)
To read Subject Name I'm using X509_get_subject_name(certificate) and for Issuer I'm using X509_get_issuer_name(certificate) and is working.
The problem is the Subject Alternative Name. I can't find any function to return this information.
Is it possible using OpenSSL to get the Subject Alternative Name? How?
Edit:
I imported the certificate into MAC keychain.
On Subject Alternative Name I see NT Principal Name and RFC 822 Name.
I tried this but it is returning NULL:
GENERAL_NAME *name = (GENERAL_NAME*)X509_get_ext_d2i(cert,NID_subject_alt_name, NULL, NULL)
I'm reading certificate with this:
X509 *cert;
CFDataRef der = SecCertificateCopyData(certificate);
const unsigned char * ptr = CFDataGetBytePtr(der);
int len = CFDataGetLength(der);
d2i_X509(&cert,&ptr,len);
You can get the x509 subject alternative name by using X509_get_ext_by_NID() then X509_get_ext() :
int loc = X509_get_ext_by_NID(X509 *, NID_subject_alt_name, -1);
if (loc >= 0) {
X509_EXTENSION * ext = X509_get_ext(X509 *, loc);
then you have to parse the extension using sk_GENERAL_NAME_num() and sk_GENERAL_NAME_value(), or X509_get_ext_d2i().

BlackBerry Decryption - BadPaddingException

I have successfully encrypted data in BlackBerry in AES format. In order to verify my result, I am trying to implement decryption in BlackBerry using the following method:
private static byte[] decrypt( byte[] keyData, byte[] ciphertext )throws CryptoException, IOException
{
// First, create the AESKey again.
AESKey key = new AESKey( keyData );
// Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block length
// we want to use a padding engine (PKCS5 in this case).
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine( engine );
// Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream( ciphertext );
BlockDecryptor decryptor = new BlockDecryptor( uengine, input );
// Now, read in the data. Remember that the last 20 bytes represent
// the SHA1 hash of the decrypted data.
byte[] temp = new byte[ 100 ];
DataBuffer buffer = new DataBuffer();
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
byte[] plaintextAndHash = buffer.getArray();
int plaintextLength = plaintextAndHash.length - SHA1Digest.DIGEST_LENGTH;
byte[] plaintext = new byte[ plaintextLength ];
byte[] hash = new byte[ SHA1Digest.DIGEST_LENGTH ];
System.arraycopy( plaintextAndHash, 0, plaintext, 0, plaintextLength );
System.arraycopy( plaintextAndHash, plaintextLength, hash, 0,
SHA1Digest.DIGEST_LENGTH );
// Now, hash the plaintext and compare against the hash
// that we found in the decrypted data.
SHA1Digest digest = new SHA1Digest();
digest.update( plaintext );
byte[] hash2 = digest.getDigest();
if( !Arrays.equals( hash, hash2 )) {
throw new RuntimeException();
}
return plaintext;
}
I get an exception thrown "BadPaddingException" at the following line
int bytesRead = decryptor.read( temp );
Can anybody please help.
I think the problem might be in this block:
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
When read returns -1, you are also writing it to the buffer. And the exit condition is also wrong. Compare that to the block in CryptoDemo sample project:
for( ;; ) {
int bytesRead = decryptor.read( temp );
if( bytesRead <= 0 )
{
// We have run out of information to read, bail out of loop
break;
}
db.write(temp, 0, bytesRead);
}
Also there are a few points you should be careful about, even if they are not causing the error:
AESDecryptorEngine engine = new AESDecryptorEngine( key );
If you read the docs for this constructor, it says:
"Creates an instance of the AESEncryptorEngine class given the AES key
with a default block length of 16 bytes."
But in the previous line, when you create the key, you are doing this:
AESKey key = new AESKey( keyData );
Which according to the docs, it "Creates the longest key possible from existing data.", BUT only "the first 128 bits of the array are used". So it does not matter what length your keyData has, you will always be using a 128 bit key length, which is the shortest of the 3 available sizes (128, 192, 256).
Instead, you could explicitly select the algorithm block key length. For instance, to use AES-256:
AESKey key = new AESKey(keyData, 0, 256); //key length in BITS
AESDecryptorEngine engine = new AESDecryptorEngine(key, 32); //key lenth IN BYTES
Finally, even if you get this working, you should be aware that directly deriving the key from the password (which might be of an arbitrary size) is not secure. You could use PKCS5KDF2PseudoRandomSource to derive an stronger key from the key material (password), instead of just using PKCS5 for padding.
Your encrypted data should be correctly padded to the block size (16 bytes).
Try to decrypt the data without padding, and see if tail bytes correspond to PKCS#5 padding (for instance, if it was needed 5 bytes of padding, it should be appended with 0x05 0x05 0x05 0x05 0x05 bytes).
The problem is that any data with the correct block size will decrypt. The issue with that is that it will likely decrypt to random looking garbage. Random looking garbage is not often compatible with the PKCS#7 padding scheme, hence the exception.
I say problem because this exception may be thrown if the key data is invalid, if the wrong padding or block mode was used or simply if the input data was garbled during the process. The best way to debug this is to make 100% sure that the algorithms match, and that the binary input parameters (including default ones by the API) match precisely on both sides.

Resources