I have working code that uses Java Bouncycastle lib that (as I understood) decrypts CMS data.
byte[] encryptedData = Base64.decode(encryptedText);
CMSEnvelopedData cmsEnvelopedData = new CMSEnvelopedData(encryptedData);
RecipientInformationStore recipients = cmsEnvelopedData.getRecipientInfos();
X509CertificateHolder decryptPublicCertificateHolder = new X509CertificateHolder(decryptPublicCertificate.getEncoded());
for (RecipientInformation recipient : recipients) {
org.bouncycastle.cms.RecipientId recipientId = recipient.getRID();
Recipient decryptRecipient = new JceKeyTransEnvelopedRecipient(decryptPrivateKey);
byte[] plainData = recipient.getContent(decryptRecipient);
String plainText = new String(plainData, getEncoding());
// ...
}
// ...
Certificate and private key are stored together in .pfx file. Encrypted message comes as string in Base64
To decrypt the message using openssl I:
Extracted cert and private key into 2 separate PEM files:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
Private key is decrypted
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
Added header/footer to encrypted message
-----BEGIN PKCS7-----
...
-----END PKCS7-----
Tried to decrypt the message
openssl cms -decrypt -inform PEM -in encrypted_message_file -inkey private_key.pem -recip certificate.pem
As a result I get
Error decrypting CMS structure
16972:error:060CC07A:digital envelope routines:EVP_CIPHER_asn1_to_param:cipher parameter error:../openssl-1.1.1e/crypto/evp/evp_lib.c:79:
16972:error:2E078066:CMS routines:cms_EncryptedContent_init_bio:cipher parameter initialisation error:../openssl-1.1.1e/crypto/cms/cms_enc.c:80
I also tried remove header/footer for encrypted message, tried provide .pfx file as private key and many more but no result
I'm very new to that stuff. Could you please suggest what am I doing wrong?
UPD1:
openssl pkcs7 -in encrypted_message_file -text produces
unable to load PKCS7 object
2496:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:1130:
2496:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:290:Type=PKCS7_ISSUER_AND_SERIAL
2496:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:627:Field=issuer_and_serial, Type=PKCS7_RECIP_INFO
2496:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:595:Field=recipientinfo, Type=PKCS7_ENVELOPE
2496:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:627:
2496:error:0D08403A:asn1 encoding routines:asn1_template_ex_d2i:nested asn1 error:../openssl-1.1.1e/crypto/asn1/tasn_dec.c:477:Field=d.enveloped, Type=PKCS7
2496:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:../openssl-1.1.1e/crypto/pem/pem_oth.c:33:
UPD2 in response to dave_thompson_085 comment
openssl asn1parse -i -in encrypted.pem
0:d=0 hl=4 l=2307 cons: SEQUENCE
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-envelopedData
15:d=1 hl=4 l=2292 cons: cont [ 0 ]
19:d=2 hl=4 l=2288 cons: SEQUENCE
23:d=3 hl=2 l= 1 prim: INTEGER :02
26:d=3 hl=4 l= 304 cons: SET
30:d=4 hl=4 l= 300 cons: SEQUENCE
34:d=5 hl=2 l= 1 prim: INTEGER :02
37:d=5 hl=2 l= 20 prim: cont [ 0 ]
59:d=5 hl=2 l= 13 cons: SEQUENCE
61:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption
72:d=6 hl=2 l= 0 prim: NULL
74:d=5 hl=4 l= 256 prim: OCTET STRING [HEX DUMP]:512_LENGTH_HEX_STRING
334:d=3 hl=4 l=1973 cons: SEQUENCE
338:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
349:d=4 hl=2 l= 12 cons: SEQUENCE
351:d=5 hl=2 l= 8 prim: OBJECT :rc4
361:d=5 hl=2 l= 0 prim: NULL
363:d=4 hl=4 l=1944 prim: cont [ 0 ]
Okay. My initial goal was to decrypt CMS message. In my case the message contains data key encrypted by rsa and content encrypted by rc-4.
I couldn't decrypt the message using Openssl, instead I used https://github.com/lapo-luchini/asn1js npm package to build ASN1 object from the CMS message, extract encrypted data key, decrypt that data key and decrypt content using that key.
I used https://datatracker.ietf.org/doc/html/rfc5652 to read about CMS structure. Also I used UI to visualize parsed message (https://lapo.it/asn1js/).
UPD1.
Eventually we decided to abandon CMS rc4. So my question is irrelevant.
No, I didn't find the way to decrypt the message via openssl (probably it's not possible since rc4 is not supported)
I decrypt it using nodejs but it was so much pain
Related
I have created a keypair
openssl genrsa -out test1 2048
then created a certificate signing request using that key
openssl req -new -key test1 -subj "/CN=foo" -out foo.csr
verifying that certificate using openssl req -in foo.csr -text
It Contains the public key of the keypair i have generated
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:ca:c5:29:98:08:05:30:30:03:08:eb:23:c2:af:
3e:2e:2d:dc:11:96:cb:2f:d1:1f:7f:41:a4:00:13:
8a:ee:4b:36:5b:f2:c1:d1:0f:8b:27:11:34:08:bd:
4d:df:7e:6d:7a:d7:f9:dd:ea:62:ad:fa:8f:8c:eb:
47:5f:55:82:2c:13:c2:11:41:12:b9:87:0b:3d:08:
86:1b:ad:71:16:89:1c:fa:07:4a:86:8f:80:a9:99:
37:f7:e2:d4:d3:d8:b2:5f:7f:c9:05:51:73:f0:c8:
59:ec:c3:09:a2:03:a5:6e:ec:8b:d9:9c:11:de:d3:
df:55:a5:3f:0c:36:d6:93:8a:70:a0:b9:61:cd:c9:
4a:09:ad:f7:3e:fd:ce:6f:5c:bb:00:69:e9:3b:3d:
85:3b:01:1d:8f:6a:a7:d4:61:f9:b5:07:1e:90:ed:
ab:3b:41:cc:db:e8:a0:e7:88:b7:77:35:66:30:b7:
a6:cd:ea:d6:12:f5:ef:82:63:e9:46:29:2e:7c:10:
0e:32:fd:04:2d:cd:62:0e:4b:74:46:f7:fd:f6:4a:
8d:fb:82:9d:37:11:50:ea:9f:f0:d6:64:2b:50:a4:
f0:18:6e:81:28:11:04:db:2a:0a:f7:b1:70:c5:78:
fe:ed:e3:55:2c:64:f4:a5:a0:96:f5:11:3a:27:2c:
5a:51
Exponent: 65537 (0x10001)
Subject attributes i have provided while creating the CSR
Subject: CN=foo
Digital Signature Information
Signature Algorithm: sha256WithRSAEncryption
92:b0:82:a5:aa:98:4a:62:5a:84:8a:15:5c:6f:48:dc:e3:ec:
7f:d5:04:e8:c1:47:55:3c:b3:57:84:16:ff:5a:0d:29:2c:16:
f2:cc:0c:18:c3:1f:d5:e1:57:3a:dd:8b:b1:c6:92:c3:fe:cb:
2b:9d:7d:79:d5:64:eb:31:00:8b:5e:77:48:ce:66:6f:dd:7b:
71:41:f9:aa:6e:ea:ea:59:e0:cd:f8:db:a9:13:18:d2:2a:fc:
12:25:b3:01:44:0c:b1:02:f7:1a:0f:d0:07:04:1d:9f:6f:a1:
58:91:87:25:4a:d6:47:a6:b5:4e:3c:a1:fd:b6:6c:c3:96:16:
c1:ab:00:d2:4c:95:ee:2c:01:2d:cf:0e:d0:62:1b:4f:0e:34:
e3:e8:85:50:63:74:eb:1f:ac:95:30:d4:df:43:7f:58:11:90:
35:29:9d:85:94:dc:c8:c2:29:81:46:71:20:62:9c:9c:f8:ef:
ed:bc:8b:e3:d5:41:b3:14:f7:43:c6:b2:74:c2:22:06:a2:af:
88:68:2e:67:c4:de:ed:61:37:41:d6:df:8a:76:7d:42:5d:98:
d3:c9:19:8b:1d:26:73:92:95:0f:ba:c1:78:3a:55:87:e0:3e:
16:13:34:6e:21:13:b9:da:b8:66:f3:0a:ec:79:ae:1a:95:6c:
04:cf:b8:b5
Following are my doubts :
what all data fields it has considered to calculate the signature ?
can we manually create the signature and verify it with the one mentioned in CSR ?
The data over which the signature is calculated is pretty much everything in the CSR except for the signature algorithm and signature. This is called the certificationRequestInfo in RFC 2986.
The second question: how do we verify the signature?
The short answer: have openssl do it for you.
The easiest way by far is to ask openssl itself to verify it:
$ openssl genrsa -out test.key 2048
$ openssl req -new -key test.key -subj "/CN=foo" -out foo.csr
$ openssl req -in foo.csr -verify -noout
verify OK
Done!
The long (and tedious) answer: do it manually
Ok, so you really want to do it manually. Let's give it a shot.
Given the above, we first need to extract the desired information from the CSR. Dumping the ASN.1 structure, we get:
$ openssl asn1parse -i -in foo.csr
0:d=0 hl=4 l= 595 cons: SEQUENCE
4:d=1 hl=4 l= 315 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
11:d=2 hl=2 l= 14 cons: SEQUENCE
13:d=3 hl=2 l= 12 cons: SET
15:d=4 hl=2 l= 10 cons: SEQUENCE
17:d=5 hl=2 l= 3 prim: OBJECT :commonName
22:d=5 hl=2 l= 3 prim: UTF8STRING :foo
27:d=2 hl=4 l= 290 cons: SEQUENCE
31:d=3 hl=2 l= 13 cons: SEQUENCE
33:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
44:d=4 hl=2 l= 0 prim: NULL
46:d=3 hl=4 l= 271 prim: BIT STRING
321:d=2 hl=2 l= 0 cons: cont [ 0 ]
323:d=1 hl=2 l= 13 cons: SEQUENCE
325:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
336:d=2 hl=2 l= 0 prim: NULL
338:d=1 hl=4 l= 257 prim: BIT STRING
This is a structured CertificationRequest defined by RFC 2986 as:
CertificationRequest ::= SEQUENCE {
certificationRequestInfo CertificationRequestInfo,
signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
signature BIT STRING
}
The certificationRequestInfo (see RFC for structure details) in DER-encoded ASN.1 format is signed using the algorithm described in signatureAlgorithm and the private key to yield signature.
Let's extract all the parts we need from the CSR. The strparse value is the offset you want to export, this is the first number on each line in the output above.
# Extract the certificationRequestInfo (data to be signed)
$ openssl asn1parse -in foo.csr -strparse 4 -out info.der
# Extract the public key.
$ openssl req -pubkey -in foo.csr -noout -out pub.pem
# Alternatively, you can use:
$ openssl asn1parse -in foo.csr -strparse 27 -out tmp.der
$ openssl rsa -pubin -inform DER -in tmp.der -out pub.pem
# Extract the raw signature bytes:
$ openssl asn1parse -in foo.csr -strparse 338 -out sig.raw
0:d=0 hl=2 l= 70 cons: cont [ 3 ]
Error in encoding
139935063934272:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:../crypto/asn1/asn1_lib.c:91:
Ignore the error on the last one, this is because the extracted data is the raw signature bytes, it's not ASN.1 encoded. openssl still happily wrote it out to the file.
We now have the following files:
info.der: the DER-encoded data that was signed
pub.pem: the CSR requester's public key
sig.raw: the signature included in the CSR
Let's verify the RSA signature (because that's what the signature algorithm says) using the public key and extract the original hash:
$ openssl rsautl -verify -pubin -inkey pub.pem -in sig.raw -out hash.der
$ openssl asn1parse -i -in hash.der -inform DER
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:192E0909DABC7454006628AA3F7FB009AFA62A17A44908CAE5E166E528DCDD11
It didn't fail, so we already know the public key is the one that matches the private key used to sign the data.
The last section, the long OCTET STRING is the raw hash of the message as computed by the CSR requester:
192e0909dabc7454006628aa3f7fb009afa62a17a44908cae5e166e528dcdd11
Let's compute the sha256 hash (once again: because the signature algorithm tells us to) of the certificationRequestInfo:
$ sha256sum info.der
192e0909dabc7454006628aa3f7fb009afa62a17a44908cae5e166e528dcdd11 info.der
Yay! The hash is equal to the one extracted from the signature.
The hashes match and the signature was signed by the private key corresponding to the public key listed in the CSR. This is a valid CSR.
Done! See, I said it would be tedious.
I know we can use openssl to do that. However that requires the private key. In my case, I don't have the private key and only have the public key. I uses Google Cloud HSM and the private key is not accessible directly. I can only download the public key. Then how can I do it?
My public key, it uses secp256r1:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhspCFgsa/oSDJajb8DvaLhLURUbD
C2UXU1E/a//ht4NMLTadhSMc195SL8YD55tPXR6bvERBrZfYEmpBlkr8BQ==
-----END PUBLIC KEY-----
Is openssl required as the solution? I cannot see a way of getting the information you ask for that way.
I got this information via a simple Java program:
EC public key, 256 bits
public x coord: 60967280926790184513158415212015267447322831299023265344568139622352475502467
public y coord: 34455661551278605550386928620071510096611427884751984970963480406192147856389
parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
The Java code:
String keyAsTxt = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhspCFgsa/oSDJajb8DvaLhLURUbDC2UXU1E/a//ht4NMLTadhSMc195SL8YD55tPXR6bvERBrZfYEmpBlkr8BQ==";
byte[] keyAsBytes = Base64.getDecoder().decode(keyAsTxt);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyAsBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
System.out.println(publicKey);
You could use:
openssl ec -pubin -noout -text -conv_form uncompressed
This will output:
Public-Key: (256 bit)
pub:
04:86:ca:42:16:0b:1a:fe:84:83:25:a8:db:f0:3b:
da:2e:12:d4:45:46:c3:0b:65:17:53:51:3f:6b:ff:
e1:b7:83:4c:2d:36:9d:85:23:1c:d7:de:52:2f:c6:
03:e7:9b:4f:5d:1e:9b:bc:44:41:ad:97:d8:12:6a:
41:96:4a:fc:05
ASN1 OID: prime256v1
NIST CURVE: P-256
04 indicating it is uncompressed (we forced this), the X and Y coordinates are just concatenated behind each other:
X (hex): 86:ca:42:16:0b:1a:fe:84:83:25:a8:db:f0:3b:da:2e:12:d4:45:46:c3:0b:65:17:53:51:3f:6b:ff:e1:b7:83
Y (hex): 4c:2d:36:9d:85:23:1c:d7:de:52:2f:c6:03:e7:9b:4f:5d:1e:9b:bc:44:41:ad:97:d8:12:6a:41:96:4a:fc:05
A possible bash pipeline could be (would need to assure openssl text cli output is stable):
| grep -E "^ +.*" | tr -d ' \n' | sed 's/^...//' | sed 's/./ /96'
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
How can I decrypt a message signed with a private key in golang?
$ openssl genrsa -out ./server/server.key
Generating RSA private key, 2048 bit long modulus
..................+++
.............................................+++
$ openssl rsa -in ./server/server.key -pubout -out ./client/client.pub
writing RSA key
$ echo "secret" | openssl rsautl -inkey ./server/server.key -sign > ./secret
# decrypt with public key
$ openssl rsautl -inkey ./client/client.pub -pubin -in ./secret
secret
I fully understood my question, it was about RSA_public_decrypt method of openssl: https://www.openssl.org/docs/man1.1.0/crypto/RSA_public_decrypt.html
I did not found any pure-golang realization. Realization with cgo: https://github.com/dgkang/rsa/blob/master/rsa/rsa.go
UPD, work for me:
func RSA_public_decrypt(pubKey *rsa.PublicKey, data []byte) []byte {
c := new(big.Int)
m := new(big.Int)
m.SetBytes(data)
e := big.NewInt(int64(pubKey.E))
c.Exp(m, e, pubKey.N)
out := c.Bytes()
skip := 0
for i := 2; i < len(out); i++ {
if i+1 >= len(out) {
break
}
if out[i] == 0xff && out[i+1] == 0 {
skip = i + 2
break
}
}
return out[skip:]
}
I think there is a bit of a misunderstanding here. openssl rsautl -sign does not encrypt the data. It produces a signature. The contents in your secret file is not "secret", encrypted. Rather, it is a signature of the text "secret" that is signed with the private key.
Using the public key, you can -verify the signature, but this isn't really what you are trying to do. It sounds like you want encrypt/decrypt, not sign/verify.
Use the -encrypt and -decrypt options of rsautl. Encryption happens with the public key, and decryption happens with the private key.
Keep in mind there are limits to the amount of data you can encrypt with RSA. Typically, you would protect a symmetric key with RSA, and use the symmetric key to do bulk encryption and decryption.
I need to use the PEM formatted public key for some purpose, but not finding the command which can convert DER formatted public key to PEM formatted public key.
The command I have used -
openssl rsa -in user_id_rsa.pub -inform DER -outform PEM -out pubkey.pem
But i got the below error -
unable to load Private Key
139901900170912:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1337:
139901900170912:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:tasn_dec.c:677:
139901900170912:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1337:
139901900170912:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:388:Type=RSA
My expected output should be in this format-
-----BEGIN RSA PUBLIC KEY-----
KEY CONTENT
-----END RSA PUBLIC KEY-----
Is anyone has try the same?
I'm using openssl library and I want to read a public key from a .pem file with BIO. I tried this, but my rsa variable remains uninitialized :
RSA *rsa = RSA_new();
BIO *keybio = NULL;
keybio = BIO_new(BIO_s_file());
BIO_read_filename(keybio, "public.pem");
// and also tried this instead of last two lines:
// keybio = BIO_new_file("public.rem", "r");
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
When I debug my application it shows me something like this:
rsa { padding = ???, n = ??? , ...}
rsa->n <unable to read from memory> and so on for all rsa fields.
My file is valid and the key is generated respecting PKCS#1 format. I parsed it with an asn1 parser.
Your code looks fine. Try this input:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1IHYYTavz9PQRxpcyO7J
m0dtiIjNUvW3coLQQKhq+wySTTN1cwm2zYTw0FSfLDPOtOBNXFwKF9wykiyHS2uU
D8vIU+T/fvlcADYTtZqdC5AoBWlSuhp0xqqtHmNUEjGa4FpRmKusL8s5/cuAfNRV
NVSxA3JCN3kYrT9Q1qBN+XbOQn+h7gPQU3ICmG7L1R/CwIsq/wwUbq+NeY0TMvz5
LM6AIS+GCV0UeJVm6UN6GDBCOHk02XuplyhkbCsNhq+HTfhHVeE1s7NcIavmgvqm
EtlIcTGemW9tXs5/REZUv+SDpR6RLUKhwuij/Ft5Pe9b7cH3wXqNmOBhJ3F/ht2C
swIDAQAB
-----END PUBLIC KEY-----
Compare this to what you see with your asn1 parser:
$ openssl asn1parse -in public.pem
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING