I just received my Covid Green Pass. I've started to decode it, here are the fields I get:
header: a20448349a42b0c2d0728e0126
payload: a4041a645d8180061a61053b9501624954390103a101a4617681aa62646e01626d616d4f52472d3130303033313138346276706a313131393334393030376264746a323032312d30372d313462636f624954626369782630314954303544314444
signature: 6f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc782cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a
All fields are hexadecimals in this example. The payload is a CBOR structure, it can be further decoded to get your data.
Verifying the GreenPass
What I would like to do now, is to verify the signature using the Unix tool openssl.
I figured out that the green pass signature is created with Elliptic Curve Digital Signature Algorithm (ECDSA), using the P–256 parameters, in combination with the SHA–256 hash algorithm.
With openssl, I should be able to verify this greenpass:
$ openssl dgst -sha256 -verify public_key_it -signature my_signature my_data
I need three parameters: public_key_it, my_signature and my_data.
public_key_it is a file containing the public key capable of checking the green pass signature. It is available online, for Italy it is:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnL9+WnIp9fvbcocZSGUFlSw9ffW/jbMONzcvm1X4c+pXOPEs7C4/83+PxS8Swea2hgm/tKt4PI0z8wgnIehojw==
-----END PUBLIC KEY-----
my_signature is a file containing the signature part of the green pass.
I get it with:
echo "6f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc782cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a" | xxd -r -p > my_signature
The my_data part is more mysterious.
It seems that it should be a Sig_structure, as specified in https://datatracker.ietf.org/doc/html/rfc8152#section-4.4.
Anyway, I tried to compose it:
jSignature1MH4Br&#Y7d]a;bIT9avbdnbmamORG-100031184bvpj1119349007bdtj2021-07-14bcobITbcix&01IT05D1DDD951474B1C93D161A4F4663B8E#3bmplEU/1/20/1507bisvMinistero della Salutebsdbtgi840539006cnamcfntfDUPONTbfnfDUPONTcgntxCORENTIN<NICOLAS<MARIE<FRANCOISbgnx"CORENTIN, NICOLAS, MARIE, FRANCOIScvere1.0.0cdobj1978-11-17
Some characters are not printable, so here it is again in hexadecimals:
846a5369676e6174757265314da20448349a42b0c2d0728e012640590137a4041a645d8180061a61053b9501624954390103a101a4617681aa62646e01626d616d4f52472d3130303033313138346276706a313131393334393030376264746a323032312d30372d313462636f62495462636978263031495430354431444444393531343734423143393344313631413446343636334238452333626d706c45552f312f32302f31353037626973764d696e69737465726f2064656c6c612053616c7574656273640162746769383430353339303036636e616da463666e74664455504f4e5462666e664455504f4e5463676e74781f434f52454e54494e3c4e49434f4c41533c4d415249453c4652414e434f495362676e7822434f52454e54494e2c204e49434f4c41532c204d415249452c204652414e434f49536376657265312e302e3063646f626a313937382d31312d3137
Well, if I try the openssl command above, I get:
$ openssl dgst -sha256 -verify public_key_it -signature my_signature my_data
Error Verifying Data
140529059103168:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:../crypto/asn1/asn1_lib.c:91:
140529059103168:error:0D068066:asn1 encoding routines:asn1_check_tlen:bad object header:../crypto/asn1/tasn_dec.c:1137:
140529059103168:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:309:Type=ECDSA_SIG
Any hint? Am I even on the right track??
Thanks
EDIT: I now solved the problem. I wrote about all the details in a blog post: http://www.corentindupont.info/blog/posts/Programming/2021-08-13-GreenPass.html
With the help of #MichaelFehr, I managed to solve this problem!
Signature conversion
The GreenPass has a signature in "raw" (P1363) format.
However, openssl only accepts DER format. So we need to convert it.
Here is my signature:
6f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc782cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a
It is 64 bytes long. It is composed of two integers, R and S.
R is the first half, while S is the second half.
R = 6f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc78
S = 2cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a
According to DER encoding, I need to add some more bytes:
30 -- fixed value for composed structure
44 -- size of everything that follows
02 -- fixed value for integer
20 -- size of the R integer
6f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc78 -- R
02 -- fixed value for integer
20 -- size of the S integer
2cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a -- S
If I assemble it, I can obtain my DER signature:
echo -n "304402206f422bd436e216177de025d3d31681a27bead6115f480630754db6f1498bbc7802202cdc975f4c4d79af77dbe02c31de6af4ba94d7fe11510a5ca6121cb0bf10890a" | xxd -r -p > my_signature.der
Data conversion
The data part needs to be composed, too.
According to the COSE spec, I need to build a "Sig_structure" from the green pass data. This Sig_structure is used both for creating the signature, and verifying it.
Here is the "Sig_structure" completed:
846a5369676e6174757265314d -- "Signature1" in hexadecimals
a20448349a42b0c2d0728e0126 -- My header (see original post above)
40590137 -- some separator... not sure
a4041a645d8180061a61053b9501624954390103a101a4617681aa62646e01626d616d4f52472d3130303033313138346276706a313131393334393030376264746a323032312d30372d313462636f62495462636978263031495430354431444444393531343734423143393344313631413446343636334238452333626d706c45552f312f32302f31353037626973764d696e69737465726f2064656c6c612053616c7574656273640162746769383430353339303036636e616da463666e74664455504f4e5462666e664455504f4e5463676e74781f434f52454e54494e3c4e49434f4c41533c4d415249453c4652414e434f495362676e7822434f52454e54494e2c204e49434f4c41532c204d415249452c204652414e434f49536376657265312e302e3063646f626a313937382d31312d3137 -- my payload (see above)
We can now create my_data:
echo -n "846a536967..." | xxd -r -p > my_data.bin
It now works!!
$ openssl dgst -sha256 -verify public_key_it -signature my_signature.der my_data
Verified OK
Related
I am trying to implement RSA algorithm and as per the algorithm public key and private keys are based on the very large numbers and the resulting, private key and public key are also a number.
For instance to generate the private key and public key
let's choose
p = 7
q = 19
n = p * q = 133
m = (p-1) * (q-1) = 108
e = 5
d = (1 + i * m) /e
for i = 0, 1, 2 .. n
d = 65
Here we get
Public key pair (n, e) = (133, 5)
Private key pair (n, d) = (133,65)
Encryption: p^e%n
Decryption: c^d%n
But. As I know the public key and private key generate by ssh-keygen command is id_rsa and id_rsa.pub.
While inspecting the id_rsa and id_rsa.pub I found the letters instead of a very large number.
How theses id_rsa and id_rsa.pub are used to encrypt the data.
As mentioned in the comments, those files are encoded in base64 format. But if you ask, what is encoded in base64, that is where things start to go in the weeds. The primary motive of files is to store some numbers that are used in the RSA calculations. They are not meant for humans to be read since it's not space friendly. They are meant for machine to process, and fast, so it has to be written in a format that machines can easily load and start using.
If you look at a standard called JWK or JSON Web Key, you will see how the keys are passed around among applications. eg:
A private key
{
"kty": "EC",
"d": "u5uui9SeGmkorTrbXtOGWAaov1cLCZXt3kleSxzH8T0",
"use": "sig",
"crv": "P-256",
"x": "a3JvmNVFxue8gyAdtH_Pca87CKjh82j7mMRzHhS3_IA",
"y": "JdEC03zi2IatFVjrp1o4ear32gBe4E0xiFf_EDt8unM",
"alg": "ES256"
}
and a public key:
{
"kty": "EC",
"use": "sig",
"crv": "P-256",
"x": "a3JvmNVFxue8gyAdtH_Pca87CKjh82j7mMRzHhS3_IA",
"y": "JdEC03zi2IatFVjrp1o4ear32gBe4E0xiFf_EDt8unM",
"alg": "ES256"
}
These might a more human readable form, but if you observe, they are in a serialized string format. They will have to go from string to JSON to field extraction and then convert them to objects which can then be used.
The files that are generated by openssl and openssh are more in the format closer to what machines like. I would recommend to use openssl to play around with openssh since they are much more wide spread. There is a spec, x509, which the world uses for cryptography to share keys around. Openssh is built on a bit different spec and they keys generated are written in a different format.
If you want to see the big numbers, there are 2 ways:
But first, lets generate a key to play around with. We will generate a 512-bit key just to keep it small.
openssl genrsa -out key.pem 512
Easy way, ask a tool to help: Given that you have the above file with you, you can ask openssl to parse it dump the info for you.
$ openssl rsa -in key.pem -noout -text
RSA Private-Key: (512 bit, 2 primes)
modulus:
00:a9:...
publicExponent: 65537 (0x10001)
privateExponent:
00:8c:...
prime1:
00:da:...
prime2:
00:c6:...
exponent1:
4e:0d:...
exponent2:
76:66:...
coefficient:
00:92:...
The numbers are ellipsis-ed just to keep it small.
Another way to look at this is:
$ openssl asn1parse -in key.pem -inform PEM
You will see the output with the huge numbers that you are expecting.
The hard way: These numbers are packed in format called ASN1. If you read the binary in the format as encoded, you will be able to see the numbers in the binaries too.
But first, need to convert the openssh keys into the required format, called the PEM format.
ssh-keygen -f id_rsa.pub -e -m pem > pubkey.pem
Now, we can do a openssl asn1parse -in pubkey.pem -inform PEM and see the details.
$ ssh-keygen -f id_rsa.pub -e -m pem | openssl asn1parse -inform PEM
0:d=0 hl=4 l= 266 cons: SEQUENCE
4:d=1 hl=4 l= 257 prim: INTEGER :EB3F998DBAE8F8AFF59FE51F2A1BCE36D76F71D0DD76FD92B77CB2FFADAF9B7F3EA77FEA40590D7C1BFEEB7DA7F72E780D79784A778761980DA7FE4C320BA513A4849929F92A2185305C379A125080C7CAFA37C53D38AD447A895EC5E3BEC77F323CB818D90F5F8071566A7618ADEA94A4FF472E21BDF782197A07DADB6DEFD6FE27D759775BEC3AFEAF973F861FD5F3A8CB1177304206A79DAFC961F7E4792E76732589BD219742F73630364C3724D5FCE3B0DC1EDD3E498549EE74ED17157E333883FAC498C8EE75F69700E2385A510BF705DE4DD5599806F47F2DDD6EA71CD0ADF50C9B943A30E2A8B6C086699A59413195CC4CA846B40460F767F4D40AE3
265:d=1 hl=2 l= 3 prim: INTEGER :010001
Please read this answer to understand how these numbers are encoded into the PEM format:
https://stackoverflow.com/a/59235177/6266958
I am trying to create a bitcoin address by following the steps shown here. However, I am getting a different hash then the one shown in step 2.
Calculating the SHA256 hash on:
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
Gives me the output:
a9ce83de3a0ff3516b7c50cdd787e9f69f152f227d93c9512774231e7132e925
The problem is according to the Bitcoin wiki I should get the following hash:
0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
Can someone explain why I am not getting the same hash as the wiki?
You are treating 0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352 as an ascii string, whereas you should be treating it as a hex representation of 32 bytes.
If you use it as a string, you get:
echo -n "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352" | openssl sha256
(stdin)= a9ce83de3a0ff3516b7c50cdd787e9f69f152f227d93c9512774231e7132e925
If you treat it as bytes, you get the right result:
echo -n "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352" | xxd -p -r | openssl sha256
(stdin)= 0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
Say password is 000000
cmd> openssl passwd -1 000000
$1$noyU0rJi$iZ7EgOhutl2aJItaBcF5v.
cmd> echo -n '000000noyU0rJi' | md5sum #cmd might be incorrect
1be6132fd5be99229741e0b88700fe95 -
md5sum hash should have 32 characters, but the hash from openssl is only 22 characters (iZ7EgOhutl2aJItaBcF5v). Why is that?
Edit: I got some downvote, would be helpful if you could explain why..
At least part of the difference you are seeing is that the output of the openssl tool is in the base64 format associated with the Unix crypt function [ https://en.wikipedia.org/wiki/Crypt_(C) ], whereas the output of the md5 function is in hexadecimal (base16).
If you look carefully, you can see that the output of md5sum only has the digits 0-9 and the lowercase letters a-f. The output of the openssl command has numbers and what appears to be the full alphabet, including upper and lowercase letters.
When you encode information more densely (base64), the length will naturally be shorter.
(Sorry in advance - my english is very bad)
I encrypted a couple of *.ts files in the past. Usually, there is a *.m3u8 with the necessary information, a key-file and the *.ts chunks.
Example:
File sources:
https://support.jwplayer.com/customer/portal/articles/1430261-aes-content-protection
M3U8:
#EXTM3U
#EXT-X-VERSION:1
## Created with Unified Streaming Platform(version=1.6.7)
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:11
#EXT-X-KEY:METHOD=AES-128,URI="oceans.key"
#EXTINF:11, no desc
oceans_aes-audio=65000-video=236000-1.ts
...
What I do next is, download the key file "oceans.key" that is specified in #EXT-X-KEY and create a hexdump of the content:
cat oceans.key | hexdump -e '16/1 "%02x" "\n"'
f571bfecfd1ab9adb05ce6fa030efd81
With the sequence number converted to HEX and left-padding 0 to fill up the '16 octet', I get the initial vector and execute this statement to decrypt the *.ts file:
openssl aes-128-cbc -d -in oceans_aes-audio\=65000-video\=236000-1.ts -out decrypted.ts -K f571bfecfd1ab9adb05ce6fa030efd81 -iv 00000000000000000000000000000001
It works like a charm. To make a long story short, I've some trouble get these files decrypted:
https://www.sendspace.com/filegroup/ajezM9HbgI3OI%2BY9%2BvUdJNnxYyXqGXX6K6jsNcrzYNc
The file named 'security' is the key file. When I hex-dump its content it is 17 octets instead of 16. Run the openssl command I get the following output:
hex string is too long
invalid hex key value
I compared the content of the file with some other files from this host and recognized that the last character is always the same (0x5e / ^). So, I removed it and tried again - my guess was that it is some kind of escape sequence / line-ending. No luck so far. The result is:
bad decrypt
140050579783384:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:
Here the complete command:
openssl aes-128-cbc -d -in media_1496546273.ts -out media_1496546273.decrypt.ts -K aaf36c79be1fad3977a4e8b19e48f038 -iv 00000000000000000000000000008E97
I thought about padding, nopadding, different cipher, ... No result so far. Chrome did play the files in flowplayer without any issues.
I would appreciate any help and hint to get on with this.
BR
Golang rsa does not have NO_PADDING?
But openssl is ok.
For encrypted data docking and other language, the encrypted data with Golang cannot decrypt normally, but the use of PHP and Openssl can be normal, later found like Golang does not support NO_PADDING decryption, seems to only PKCS1.
Openssl increase the parameter - raw can normal decryption.The private key is above, a cipher and decrypted correct value.
Can someone help me to look at how to solve?
$ cat private.pem
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANJS/xu+NtmDqobnhCdLjWk46aYbBk/mQrLcozAIbQLFG2mgkrxf
B5+CgtISKpKfmRfCO2NhceK+YedaMMBUxn8CAQMCQQCMN1S9KXnmV8cEmlgaMl5G
JfEZZ1mKmYHMkxd1WvNXLNuke9ntKwti8zG1lAFcOVHnm/uYsNdua+lvvQlEgBUL
AiEA/c8ezGaNUFwEAltwTEFtFItT5PyOXlWIdPAZ7j160lkCIQDUI8f/chEmLxG1
5kPcRtyJsQRdAcnQZ5QOz6S0nBnUlwIhAKk0vzLvCOA9WAGSSt2A82MHjUNTCZQ5
BaNKu/Qo/Iw7AiEAjW0v/6FgxB9hI+7X6C89sSCtk1aGiu+4Cd/DIxK74w8CIB4q
rA1k247JrqKTGlqSHVr1Ta+h3BPbwFKCi5CiDOjV
-----END RSA PRIVATE KEY-----
$ xxd data.txt
00000000: 6d4b 5dab 6d64 45e1 e4cb 0ea8 20df b724 mK].mdE..... ..$
00000010: cfe5 db3e 75c4 e80e 2337 4f08 1b36 87b4 ...>u...#7O..6..
00000020: 7550 47d4 ed60 576a a160 2d01 3cf7 4c50 uPG..`Wj.`-.<.LP
00000030: 7e44 6432 1f9d cfe2 2e9f 4f89 f815 ae01 ~Dd2......O.....
$ base64 -i data.txt
bUtdq21kReHkyw6oIN+3JM/l2z51xOgOIzdPCBs2h7R1UEfU7WBXaqFgLQE890xQfkRkMh+dz+Iun0+J+BWuAQ==
$ cat data.txt | openssl rsautl -decrypt -inkey private.pem -raw
qYnYKT2mxuXR5XB615gOenqxOnIUjWs7
Decrypting a ciphertext block using rsa with no padding is a single modulo exponent operation.
c := new(big.Int).SetBytes(cipherText)
plainText := c.Exp(c, privateKey.D, privateKey.N).Bytes()
A full example using your input data is here: https://play.golang.org/p/CgLYgLR61t
If you want a full version of the decryption function, with side-channel blinding and using precomputed CRT values for faster performance, you can copy the decrypt function from the crypto/rsa/rsa.go source.
If you have the choice, you should not be using rsa in this manner. There is a good discussion on the Crypto StackExchange site explaining the details and drawbacks of using this method.
Not actually answer the question, but I put this here for someone who are looking for encrypting a plain text using rsa with no padding.
var publicKey *rsa.PublicKey
// ...
// ...
c := new(big.Int).SetBytes([]byte(text))
encryptedBytes := c.Exp(c, big.NewInt(int64(publicKey.E)), publicKey.N).Bytes()
encryptedBase64 := base64.StdEncoding.EncodeToString(encryptedBytes)