Manually verify PKCS#7 self signed data OpenSSL

Manually verify PKCS#7 self signed data OpenSSL

Steps to encrypt and verify:

1.Generate certificate and private key:

openssl req -x509 -newkey rsa:1024 -keyout keyfile.key -out certificate.cer -nodes -subj “/CN=testcert”

Here ,

openssl req : certificate request and certificate generating utility.

-x509

this option outputs a self signed certificate instead of a certificate request. This is typically used to generate a test certificate or a self signed root CA. The extensions added to the certificate (if any) are specified in the configuration file.

 

newkey arg

this option creates a new certificate request and a new private key. The argument takes one of several forms. rsa:nbits, where nbits is the number of bits, generates an RSA key nbits in size. If nbits is omitted, i.e. -newkey rsa specified, the default key size, specified in the configuration file is used.

-keyout filename

this gives the filename to write the newly created private key to. If this option is not specified then the filename present in the configuration file is used.

-out filename

This specifies the output filename to write to or standard output by default.

-nodes

if this option is specified then if a private key is created it will not be encrypted.

-subj arg

sets subject name for new request or supersedes the subject name when processing a request. The arg must be formatted as /type0=value0/type1=value1/type2=…, characters may be escaped by \ (backslash), no spaces are skipped.

Here ,

CN
the certificate owner’s common name

2. Write following text to a sample file:

echo “Alice still in wonderland” > data.txt

3. Self-signing data file:

openssl smime -sign -md sha1 -binary -in data.txt -out data.txt.signed -outform der -inkey keyfile.key -signer certificate.cer

Here ,

openssl smime : It can encrypt, decrypt, sign and verify S/MIME messages.

-sign

sign file “data.txt” using the supplied certificate (certificate.cer)and private key(keyfile.key). Input file(“data.txt”) is the message to be signed. The signed message in MIME format is written to the output file(“data.txt.signed”).

-md sha1

digest algorithm to use when signing or resigning. If not present then the default digest algorithm for the signing key will be used . Here algorithm used will be “sha1”

-outform SMIME|PEM|DER

this specifies the output format for the PKCS#7 structure. The default is SMIME which write an S/MIME format message. PEM and DER format change this to write PEM and DER format PKCS#7 structures instead. This currently only affects the output format of the PKCS#7 structure, if no PKCS#7 structure is being output (for example with -verify or -decrypt) this option has no effect.
4. openssl x509 -inform pem -in certificate.cer -noout -pubkey > pubkey.pem

(dd if=data.txt.signed of=signed-sha1.bin bs=1 skip=$[ 850 + 3 ] count=128)

x509 – Certificate display and signing utility

-inform DER|PEM|NET

This specifies the input format normally the command will expect an X509 certificate but this can change if other options such as -req are present. The DER format is the DER encoding of the certificate and PEM is the base64 encoding of the DER encoding with header and footer lines added.

-in filename

This specifies the input filename to read a certificate from

-noout

this option prevents output of the encoded version of the request.

-pubkey

outputs the certificate’s SubjectPublicKeyInfo block in PEM format.
5. openssl rsautl -verify -pubin -inkey pubkey.pem < signed-sha1.bin > verified.bin

rsautl The rsautl command can be used to sign, verify, encrypt and decrypt data using the RSA algorithm.

-verify

verify the input data and output the recovered data.

-pubin

the input file is an RSA public key.

-inkey file

the input key file, by default it should be an RSA private key.

 

 

 

6. openssl asn1parse -inform der -in verified.bin

// Results in the hash of the signed attributes
For reference, in my case: 82C9772D39C0943A3BF0EA131055219DAEE5FE2F

7.Find the offset and length of the signed attributes
openssl asn1parse -inform der -in data.txt.signed -i
564:d=4 hl=4 l= 413 cons: SEQUENCE
568:d=5 hl=2 l= 1 prim: INTEGER :01
571:d=5 hl=2 l= 32 cons: SEQUENCE
573:d=6 hl=2 l= 19 cons: SEQUENCE
575:d=7 hl=2 l= 17 cons: SET
577:d=8 hl=2 l= 15 cons: SEQUENCE
579:d=9 hl=2 l= 3 prim: OBJECT :commonName
584:d=9 hl=2 l= 8 prim: UTF8STRING :testcert
594:d=6 hl=2 l= 9 prim: INTEGER :DF6A0ED03F978DE4
605:d=5 hl=2 l= 9 cons: SEQUENCE
607:d=6 hl=2 l= 5 prim: OBJECT :sha1
614:d=6 hl=2 l= 0 prim: NULL
616:d=5 hl=3 l= 216 cons: cont [ 0 ]

-i

indents the output according to the “depth” of the structures.

8. Extract the signed attributes, it’s the cont[0] in the SignerInfo, just after the certificate:

dd if=data.txt.signed of=signed-attribs.bin bs=1 skip=616 count=$[ 3 + 216 ]
9. Change the ASN.1 SEQUENCE to a SET by changing the first byte to 0x31

echo -ne “\x31” | dd conv=notrunc bs=1 count=1 of=signed-attribs.bin
10. Hash the signed attributes, the result can be compared to the hash from 6.
Thereby verifying the signed attributes are signed by the public key provided in 5.
However, this doesn’t verify the actual data!!

sha1sum signed-attribs.bin

11. Note the hash from the signed attributes, run the command from 7. again and look for something like this
675:d=6 hl=2 l= 35 cons: SEQUENCE
677:d=7 hl=2 l= 9 prim: OBJECT :messageDigest
688:d=7 hl=2 l= 22 cons: SET
690:d=8 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:07D30079798D71F28813C16419166FC0CBA35BE6
12. Verify the message digest of the actual data

sha1sum data.txt
07d30079798d71f28813c16419166fc0cba35be6 *data.txt

Encrypt/Decrypt string in C#

public static string Encrypt(string data)
{
try
{
byte[] encData_byte = new byte[data.Length];
encData_byte = Encoding.UTF8.GetBytes(data);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
catch (Exception e)
{
CLogger.WriteLog(ELogLevel.ERROR, “Exception: ” + e.ToString());
throw new Exception(“Error in base64Encode ” + e.Message);
}
}

public static string Decrypt(string data)
{
try
{
UTF8Encoding encoder = new UTF8Encoding();
Decoder utf8Decode = encoder.GetDecoder();

byte[] todecode_byte = Convert.FromBase64String(data);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
catch (Exception e)
{
CLogger.WriteLog(ELogLevel.ERROR, “Exception: ” + e.ToString());
throw new Exception(“Error in base64Decode ” + e.Message);
}
}

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *