I have been able to OpenSSL tools to extract the certificate and private key bytes from an existing PFX (PKCS12) file.
However, I wish to do this using .NET. I am able to use the X509Certificate classes to load a PFX file and extract the certificate bytes but, I do not know how to extract the private key. The certificate (exported as a PFX file) was created using a sha1RSA aignature algorithm.
I know RSA classes exist in .NET but I do not know how to use them together.
Any advice will help.
Thanks in advance.
Subbu
See my answer here: extract private key bytes in C#
Does this work for you?
Related
I created PGP key pair and I exported private and public key files. I know that files are fine because I was able to encrypt/decrypt files in GpgFrontend app using these keys. I was also able to do the same using Bouncy Castle library in C#.
Two questions:
1: In Kleopatra, I can't encrypt file with Public Key only. For some reason it doesn't work. Option is not available. To be able to encrypt/decrypt I have to load Private key. What is it that I am missing?
2: I am confused with encrypted data. When I open encrypted PGP file, data looks something like this:
…F†u—PEÛ Ù×´‡Ó"gÆx=ÑoãÝSŒ6M)!ÑÙ×g|;ä #+Pa,²TDV„ëùqá²*”—}×±dCÐÊsf^:Š†7¶LØnš{‹‰ždºV°G(¸7Rd ôUµD#9ÖÕ÷ü Ý dëE¶-ýû¾/khØÇ~Zˆ0:±ðU5É¥žÇé¯7M Ôà}Ò:ÕÈàÒ€snœ‘èÁq§ÀJ®zU’èDc%ߘ–yí|걫M„ð™=Üæ0ß| 5|¾ªô Åíú_lªkó‰Ùª>/–þ€ÈðkvÖwãz9Y±ŠÜW½ìFÍþ{ãFÔS fýâÚÐpá
8Z_.eÄŽÂU)õœ-•êSQÁ\¼—? ¥ã¢O¯J•ÔÖ D;<kÔPÚ.8ÀKƒNÒ€3túø°ÒºA¼ ‡KèÁ›X
but, when I use Notepad option in Kleopatra (or in GpgFrontend), and when I encrypt some text, encrypted data looks like this:
-----BEGIN PGP MESSAGE-----
hF4D1F0XuQWmdMYSAQdAJaVSF+2pME685EMW2M/xDKPKE6BxJiSYSgP06GGKUVgw
P+7Y91/iMOHz2dB4K2clkjgLbWXvy+DRlkBKXGzs7lSK6c3+HFv1L+EIj+mm+dni
1MAGAQkCEP6UbLZfq+aFWK3Fs4H7j05XYdovJvZv9GKEBQCbGT4PjB1ZrxkC+VfO
ybB5R6cWJMdo1mdUg05KAAfSinOM/19gXBrh2pwO/snX/bK7M1iA+qi0rYcGl7Lu
ijHm6PA1c8LBMKFz7Xc6lcA5CtsLTseHHHGEtQCt6Hd/z0EvQUA0FdiYKcieX/lA
W8y0V+Xjao86VmRNYVryx6pRmbq5+vN7H/9hnDNUxgzxVb/yQ90FePzDK73V/bsT
Im2MNTma9ruB
=j0ZY
-----END PGP MESSAGE-----
Why does encrypted data look different?
Thank you
Can PEM_read_X509 function read in a CA cert file with private key properly? is it intelligent enough to handle the private key section? Or it will error out if the .pem file contains the private key?
TLDR: YES
Almost all OpenSSL PEM_read[_bio]_XYZ functions will accept a file (or equivalent) containing other data before and/or after the PEM block of type XYZ, and ignore the other data as long as it's not on the same line(s). This is designed to allow 'comments' that describe the PEM data, but also works for other types of PEM data or just arbitrary data not related to the PEM data at all. In particular PEM_read_X509 will read the first block of type CERTIFICATE, X509 CERTIFICATE, or TRUSTED CERTIFICATE and ignore anything and everything else, including a private key block.
Similarly PEM_read_[algo_or_PKCS8]PrivateKey will read the first block of type [ENCRYPTED|RSA|DSA|EC] PRIVATE KEY and ignore everything else, but fail if you tried to read a specific algorithm and the (first) private key block found was a different type. (It also fails, of course, if a valid block is found but is encrypted by a password and you don't provide the correct password either as an argument or via a callback. And if no valid block is found.)
I'm not sure if by 'CA cert' you mean a cert for a CA, or a cert issued by a CA and for an end-entity like your webserver or mailbox. Except for a personal/local or test CA you or a colleague or your organization set up, most ordinary users should have the certs for one or more CAs but never their privatekeys. And if someone responsible for a real CA like say LetsEncrypt was asking such basic questions on Stackoverflow I would be greatly alarmed and worried over the competence and thus security of that CA.
I need to support Diffie Hellman encryption, now in order to test this i need to create a certificate with DH key parameters eg. key-length - 2048 etc.
Now as i understand DH doesn't work with self-signed certificates, so basically i need to create a certificate issued by some trusted third party containing DH key parameters.
I searched a lot but can't seem to find proper direction, no where can i find a way to create a cert with DH parameters.
Can someone point me in right direction?? Thanks in advance!!
I need to support Diffie Hellman encryption
DH is key exchange (or key agreement) protocol, not encryption. DH is used to securely generate a common key between two parties, other algorithms are used for encryption itself.
I need to create a certificate with DH key parameters eg. key-length - 2048 etc
There is nothing like DH parameters in a certificate.
DH is only one of ways how a public key can be used. You may generate a DH public key with specified length (e.g. 2048 bit) and execute the DH exchange, but it has nothing to do with certificate parameters. (didn't you mean to generate a keypair, not a certificate?).
Indeed the DH key exchange needs other parameters (p, g), but the parameters are part of the protocol, not the certificate. In TLS even the DH parameters can be random and authenticated by the certificate's public key - it is called Ephemeral Diffie-Hellman key exchange.
You could generate DH parameters (p, g) separately:
openssl dhparam -out dhparams.pem 4096
Can someone point me in right direction??
Now I assume you want to establish an encrypted channel (TLS) using DH. The easiest way would be to specify allowed parameters for SSL for the library. This is an example httpd configuration, where you can enforce DH key exchange. Every reasonable SSL framework or server has option to set the parameters.
If you want to do the DH key exchange yourself (not as part of TLS), I'd advice to use an out-of-box mature library for your programming language.
Yes, it seems true that OpenSSL will not create a certificate for DH keys. You'll get an error like: operation not supported for this keytype. The reason someone would want to do this is that they want to store the DH public key in a keystore; which seems like a reasonable place to store them. In my case, I want my client application to be deployed with the server's public DH key. The problem is that keystores don't let you store public keys in them. They do however, let you store certificates in them. Hence the need for creating a certificate that contains a DH public key. Since you can't do this using OpenSSL, you'll have to do it in code. Here's the code that I use to create a certificate. If you pass in a DH public key, you'll be able to add this certificate to a keystore:
public X509Certificate createCert (PublicKey publicKey, PrivateKey caKey, X509Certificate caCert , String subject) throws Exception {
Date now = new Date();
Date exp = new Date(now.getTime()+2555*86400*1000); // 2555 days validity
BigInteger.valueOf(now.getTime());
ContentSigner signer = new JcaContentSignerBuilder("SHA256with"+caKey.getAlgorithm()).build(caKey);
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
byte[] enc = new X509v3CertificateBuilder(
/*issuer*/ new X500Name(caCert.getIssuerX500Principal().getName()),
/*serial*/BigInteger.valueOf(now.getTime()),
/*validity*/now, exp,
/*subject*/new X500Name (subject),
/*spki*/subPubKeyInfo).build(signer).getEncoded();
X509Certificate cert = (X509Certificate)CertificateFactory.getInstance ("X.509") .generateCertificate(new ByteArrayInputStream(enc));
return cert;
}
The code uses several BouncyCastle classes. Besides passing in the DH public key, you have to pass in the CA private key and the CA certificate and a String that contains the subject for the certificate that you generate. Hope that helps for those wanting to store a DH public key in a keystore.
I'm working on Apple Pay payment token decryption.
According to this instruction Payment Token Format Reference on step 2. I need use publicKeyHash field from header of payment token to determine which
merchant certificate was used by Apple.
pulbicKeyHash is SHA–256 hash of the X.509 encoded public key bytes of the merchant’s certificate, Base64 encoded as a string.
I have one merchant certificate. So I assume that if i will take sha-256 hash of my certificate's public key and Base64 encode it i will get the same value that i receive in publicKeyHash field of payment token.
But I can't figure out what particular part of the certificate should I hash.
The initial merchant certificate provided by Apple is in .cer format.
I'have extracted public key from it to .pem format. Than i have tried both take hash -> base64encode of public key (String between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----) and
to take hash of base64 decoded .pem which i think should be .der and base 64 encode it.
And both failed to match value received from Apple Pay. Also it have different length my base64 encoded hash have 88 char length, and publicKeyHash field is 44 char in length.
When I have tried to base 64 decode publicKeyHash, I've got unreadeble characters like "D��$�f���#c���$����WP��"
But according to Apple documentation there should be sha-256 hash which can not contain such symbols.
Can somebody explain me what concrete steps should I perform in order to complete this merchant certificate check?
In my case the main problem and solution was to use Payment Processing Certificate's public key hash and NOT Merchant Identity Certificate's public key hash, witch I was trying to compare with PublicKeyHash from payment token.
In my excuse I can say that following text from Apple Documentation is pretty much ambiguous:
publicKeyHash SHA–256 hash, Base64 encoded as a string Hash of the
X.509 encoded public key bytes of the merchant’s certificate.
As we have two kind of certificates merchant and payment processing. It was obvious for me that merchant certificate from documentation is merchant id certificate.
Only after re-read Payment Processing certificate description
Payment Processing Certificate. A certificate used to securely
transfer payment data. Apple Pay servers use the payment processing
certificate’s public key to encrypt the payment data. Use the private
key to decrypt the data when processing payments.
from Apple Pay JS documentation I have realized my mistake.
So I hope my experience can help somebody not to step on the same rake)
Its shame I was not able to find openssl command to extract hash directly from the cert. So you have to create the public key first in order to get the public key hash. There are two ways to extract the public key.
Step 1
A. From your ecc private key (payment processing private key)
openssl ec -in ecc_private_key.key -pubout -out ec_public_key.pem
OR
B. From the cert downloaded from apple pay portal (after uploading payment processing csr)
openssl x509 -inform der -in apple_pay.cer -pubkey -noout > apple_pay_public_key.pem
Both will give you public key in following format
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENGbyXUzeZTdeyyNuXyc0nMzXmnLl
xMwd/t/sCZr3RPhytPbZpR/V4/xHqN/MVzozzq30I0/eUefbThEBl236Og==
-----END PUBLIC KEY-----
Step 2
You can use following code to extract the base64 hash from above public key remember to remove headers/footers and line feeds.
I hoped I could have figured out how to use openssl tool to get hash from public key but anyway following c# code works for me. its very simple and easy to port to java/python/php or whatever your preference is. Or just use following code online at ideone.com
String publicKeyBase64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENGbyXUzeZTdeyyNuXyc0nMzXmnLlxMwd/t/sCZr3RPhytPbZpR/V4/xHqN/MVzozzq30I0/eUefbThEBl236Og==";
byte[] publicKey = Convert.FromBase64String(publicKeyBase64);
SHA256 sha256 = SHA256Managed.Create();
byte[] hash = sha256.ComputeHash(publicKey);
String publicKeyHash = Convert.ToBase64String(hash);
Console.WriteLine("Result: {0}", publicKeyHash);
Please keep in mind that your system should be able to accept multiple keys at any given time and instead of just verifying you need to load the correct private key based on publicKeyHash you receive from device(iphone/ipad etc) considering the scenario when your current certificate is expiring (or you are revoking for any reason) otherwise your system may not be able to accept the transaction for a short period of time. As per one of my encounter it took apple more than one hour, before new payment processing keys became active, after pressing activate in the portal.
This question and the accepted answer were still a bit vague on details, so here is exact tested method in java to check that token.paymentData.header.publicKeyHash matches Apple Pay Payment Processing Certificate:
private static void checkPublicKeyHash(String publicKeyHash, X509Certificate paymentProcessingCertificate)
throws NoSuchAlgorithmException, CertificateException {
String certHash = Base64.getEncoder().encodeToString(
MessageDigest.getInstance("SHA-256").digest(
paymentProcessingCertificate.getPublicKey().getEncoded()));
if (!Objects.equals(publicKeyHash, certHash)) {
throw new DigestException(String.format(
"publicKeyHash %s doesn't match Payment Processing Certificate hash %s",
publicKeyHash, certHash));
}
}
First it seem the answers to the original question are several months apart. Second all answers seem to lack one critical bit of information; the only reason for step 2 of the the Payment Token Format Reference is that you can have more than one Payment Processing Certificate in use. If you do then apple may use anyone to encrypt the data.
If you have just one Payment Processing Certificate then you can skip this step and just use the its private key. After all, the end result of step two is to get the private key of the payment processing certificate that was used to encrypt the payment data.
I'm trying to get certificates and private keys from windows certificate store using MSCAPI provider, then i need to store them in a Java Keystore object, but i'm facing a problem of private keys format, the error says:
java.security.KeyStoreException: Cannot get key bytes, not PKCS#8 encoded
Here's my code:
SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
PrivateKey privateKey = null;
X509Certificate cert = null;
cert = (X509Certificate) ks.getCertificate("ALIAS");
if (ks.isKeyEntry("ALIAS")) {
privateKey = (PrivateKey) ks.getKey("ALIAS", null);
}
KeyStore newKs = null;
...
...
newKs .setKeyEntry("pvKey", privateKey , "pwd".toCharArray(), certifChain);
Also, the privateKey.getEncoded() returns null.
I have exactly the same issue when programatically importing a pfx file into the windows certificate store and then attempting to read this certificate and key again later. I believe the answer lies in http://www.oracle.com/technetwork/articles/javase/security-137537.html and I quote: "...the resulting PKCS#12 keystore may not be imported into applications that use only a single password for the keystore and all its key entries". Earlier in the document it also states: "Note that keys produced by the SunMSCAPI provider are wrapper objects for the native handles. Thus, they may not be accepted by other providers and may behave somewhat differently than keys produced by pure-Java providers, such as SunJCE. In particular, the RSA private keys generated by the SunMSCAPI provider cannot be serialised". Upon trying to read the private key results in null algorithm and null encoded data as you note above, though reading the certificate works fine. Alternatively you could save the PrivateKey in a separate RSA encrypted file instead of the windows certificate store or just work of the original pfx file instead of importing the pfx into the windows certificate store.
I use command such like:
Runtime.getRuntime().exec("openssl pkcs8 -topk8 -nocrypt -in "+ privateKeyPath + " -out " + pkcs8PrivateKeyPath)