"traditional private key format" vs PKCS8 - c

The man page for PEM_write_PrivateKey states that it writes the private key using the traditional private key format.
How is this related to PKCS8 and PKCS1?

The documentation that you are referring to does not seem to be accurate (anymore). Nowadays, PEM_write_PrivateKey() does the same thing as PEM_write_PKCS8PrivateKey() for the OpenSSL implementations of RSA, DSA and EC keys.
As often the case with OpenSSL, the source code is a more reliable way to get your information. Looking at PEM_write_bio_PrivateKey(), which is supposed to give the "traditional" format according to that documentation, we see:
int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u)
{
if (x->ameth == NULL || x->ameth->priv_encode != NULL)
return PEM_write_bio_PKCS8PrivateKey(bp, x, enc,
(char *)kstr, klen, cb, u);
return PEM_write_bio_PrivateKey_traditional(bp, x, enc, kstr, klen, cb, u);
}
Indeed there is mention of a traditional private key write function, but only if the priv_encode method is not implemented for that particular key type. But it actually is implemented for the standard key types. For 1.0.2g, the version you are using according to your comment below, you can see the associated functions here: rsa_priv_encode(), dsa_priv_encode() and eckey_priv_encode(). PKCS#8 is the standard format when writing private keys.
PKCS#8 is capable of capturing multiple kinds of keys. Its format includes the option to store private keys in an encrypted form. This is different from older formats, where the encryption of the key happened at the PEM level, using a weaker encryption schema. See this answer to the SO question Password callback for reading public key with OpenSSL API for a more elaborate explanation on that in the case of RSA, comparing it to PKCS#1.
The "traditional" key format in your question refers to non-PKCS#8 key formats, which are standard in the case of RSA and EC keys and OpenSSL-specific for DSA, but are not uniform. For RSA keys, that happens to be a format often referred to as the PKCS#1 format. See also this answer to the SO question PKCS#1 and PKCS#8 format for RSA private key for more information.
If you want to write in the "traditional" formats, you will have to explicitly invoke the associated functions, like for example PEM_write_RSAPrivateKey(). In this case, the documentation does seem accurate (except for the grammatical error :-) ):
The RSAPrivateKey functions process an RSA private key using an RSA
structure. The write routines uses traditional format.

Related

Import public key using Windows C CNG/Crypto API

I need to verify a signature on multiple platforms, say Windows and Linux.
I am open to any public key format as long as I can write a platform-specific C code that can verify this signature using the provided public key (the same public key for all platforms).
It looks to me that PKCS#1 ASN.1 DER format is the most standard one, so I assume I should use it for the public key (this article provides some introduction on possible formats).
My problem is importing this public key in Windows.
It looks like this is supported in C# (e.g. see here), but I couldn't find any Windows C/C++ function that can read a public key in PKCS#1 ASN.1 DER or PEM format and convert it to its BLOB structure, probably I didn't search good enough.
A similar stackoverflow question seems to be talking about certificates, while I just need to deal with a bare public key.
Is there any CNG or CryptoAPI function that could read this (or other) format and convert it to either DSA BLOB or RSA BLOB structure? (If given a choice, I'd prefer to use CNG functions instead of CryptoAPI deprecated ones).

how to openSSL 1.1.1 ECDH with 25519

i need to implement ecdh with 25519 using openssl.
using:
key = EC_KEY_new_by_curve_name(NID_X25519)
fails.
using this:
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
EVP_PKEY_keygen_init(pctx);
EVP_PKEY_keygen(pctx, &pkey);
seems to work but i have no idea how to export the public key in uncompressed bin format. or how to import the other sides public key.
any help?
Importing the other side's public key from raw binary format can be done with the EVP_PKEY_new_raw_public_key() function. Man page here:
https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_public_key.html
Exporting the public key in raw binary format is a little more tricky since there is no function to do it. You can do it in SubjectPublicKeyInfo format using i2d_PUBKEY() described here:
https://www.openssl.org/docs/man1.1.1/man3/i2d_PUBKEY.html
Fortunately the SubjectPublicKeyInfo format has the raw public key as the last 32 bytes of its output. So you can use i2d_PUBKEY() and just use the last the 32 bytes.

How to generate a finger print for a public key to validate the public key?

I need to validate the incoming connection in my application. The incoming connection will be sending a public key and the finger print of the public key. I need to validate this public key by calculating the finger print for the public key and then compare the calculated finger print with the finger print sent by the client. I am not able to find a way to calculate this finger print for the public key. I am using open-ssl library in C platform.
Any help regarding the calculation of this finger print of the public key will be very much appreciated.
I computed SHA1 hash which can be used as fingerprint as following:
X509 * cert = ... /*Initialize certificate*/
unsigned char buffer[SHA1_DIGEST_LENGTH];
X509_check_purpose (cert, -1, 0);
/*Copy sha1_hash from the certificate.*/
memcpy(abuffer, rCert->sha1_hash, SHA1_DIGEST_LENGTH);
I hope this would help you.

JDO + PostgreSQL Arrays

I've implemented store_mapping extension but it currently uses ObjectAsStringMapping. As a result I can read array values from database but any insert or update causes underlying postgresql driver error "INTEGER[]" is not "VARCHAR".
Is there any way to implement PGSQL arrays in JDO? It looks quite flexible with all that extension points. Any hints on extension points I have to implement are appreciated, thanks in advance!
Edit:
I'm using postgres int8 as a bit field as a "replacement" for arrays after I figured out that I'll be okay with 63 possible values.
Sample class would be:
#PersistenceCapable(detachable="true", table="campaigns")
public class Campaign implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
public Long id;
public List<Integer> regions;
}
And I think I have to implement some mapping from List to java.sql.Array but still didn't figure out how to do that. I could write extension and override default behavior but what extension-point should it be?
Looks like you need to build a custom field strategy to handle the mapping.
The key then is to transform the representation in this case to PostgreSQL array representation, namely a comma separated value (with " escaping text with any special characters but can be used on all values, double quotes are escaped by doubling them). The string is then bracketed betweed { and }. So ARRAY[1,2,3]::int[] becomes '{1,2,3}' or '{"1","2","3"}'

Fileformat for EC public/private keys?

If I wanted to store both a private and a public key in a single file, what would be the easiest format to use? Especially if I'm planning to use the BouncyCastle library for Java?
On a theoretical point of view, the public key can be recomputed from the private key (computational cost for that is slightly lower than the cost for producing a single ECDSA signature, or doing half of ECDH, so it is fast). Therefore, conceptually, you only have to store the private key, and the standard format for that is PKCS#8, which is supported by Java with java.security.spec.PKCS8EncodedKeySpec. Moreover, the PKCS#8 format includes provisions for optionally encoding the public key along the private key in the same blob, so this really looks like what you are looking for.
The tricky thing, however, is to convince the cryptographic provider (e.g. BouncyCastle) to extract the public key as such and/or recompute it. Apparently, if you create a PKCS8EncodedKeySpec from a PKCS#8-encoded EC private key which also contains the public key, BouncyCastle will be kind enough to internally keep a copy of the encoded public key and write it back if you decide to reencode the private key in PKCS#8 format. However, it does nothing else with it; it handles it as an opaque blob.
Hence you must recompute the public key. Wading through the JCE and BouncyCastle API and unimplemented bits, I found the following, which appears to work (JDK 1.6.0_24, BouncyCastle 1.46):
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Provider;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.provider.JCEECPrivateKey;
import org.bouncycastle.jce.provider.JCEECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
// Create the provider and an appropriate key factory.
Provider pp = new BouncyCastleProvider();
KeyFactory kf = KeyFactory.getInstance("EC", pp);
// Decode the private key (read as a byte[] called 'buf').
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(buf);
PrivateKey sk = kf.generatePrivate(ks);
// Recompute public key.
JCEECPrivateKey priv = (JCEECPrivateKey)sk;
ECParameterSpec params = priv.getParameters();
ECPublicKeySpec pubKS = new ECPublicKeySpec(
params.getG().multiply(priv.getD()), params);
PublicKey pk = kf.generatePublic(pubKS);
// To reencode the private key.
buf = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class).getEncoded();
Conceptually, I should use kf.getkeySpec() with org.bouncycastle.jce.spec.ECPrivateKeySpec instead of ruthlessly casting the private key to the JCEECPrivateKey class, but the clean method appears not to be implemented yet in BouncyCastle.
Try this (BouncyCastle v1.47, using JDK 1.7.* but I assume JDK 1.6.* will be fine too):
// Recreate the private key.
final KeyFactory kf = KeyFactory.getInstance("EC", "BC");
final PKCS8EncodedKeySpec encPrivKeySpec = new PKCS8EncodedKeySpec(rawPrivKey);
final PrivateKey privKey = kf.generatePrivate(encPrivKeySpec);
final byte[] rawPrivKey = privKey.getEncoded();
// Recreate the public key.
final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(rawPubKey);
final PublicKey pubKey = kf.generatePublic(pubKeySpec);
final byte[] rawPubKey = pubKey.getEncoded();
where rawPrivKey and rawPubKey are arrays of byte type.
I suggest you encrypt the encoded private key with a block cipher (i.e. AES) otherwise the file is subject to be stolen and then you are indefinitely exposed.

Resources