-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
scripts to do interoperability testing with OpenSSL
- Loading branch information
Showing
6 changed files
with
494 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
Tools that allow use of the OpenSSL Encapsulation and Decapsulation API. | ||
|
||
To enable support for PQC algorithms in OpenSSL install oqsprovider and | ||
modify the `openssl.cnf` file to enable the oqsprovider: | ||
``` | ||
[provider_sect] | ||
default = default_sect | ||
oqsprovider = oqsprovider_sect | ||
[oqsprovider_sect] | ||
activate = 1 | ||
``` | ||
|
||
To generate the private (decapsulation) key using OpenSSL: | ||
``` | ||
openssl genpkey -out private-key.pem -algorithm mlkem512 | ||
``` | ||
(See other algorithm names in https://github.com/open-quantum-safe/oqs-provider) | ||
|
||
To extract the public (encapsulation) key using OpenSSL: | ||
``` | ||
openssl pkey -pubout -in public-key.pem -out pub.pem | ||
``` | ||
|
||
Compile the encapsulation and decapsulation helper apps: | ||
``` | ||
gcc -o openssl-decap -lcrypto openssl-decap.c | ||
gcc -o openssl-encap -lcrypto openssl-encap.c | ||
``` | ||
|
||
To encapsulate a shared secret: | ||
``` | ||
./openssl-encap -k public-key.pem -s secret.bin -c ciphertext.bin | ||
``` | ||
|
||
To decapsulate a shared secret: | ||
``` | ||
./openssl-decap -k private-key.pem -s secret-dec.bin -c ciphertext.bin | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import sys | ||
|
||
if len(sys.argv) != 4: | ||
raise ValueError(f"Usage: {sys.argv[0]} dk.pem secret.bin ciphertext.bin") | ||
|
||
from kyber_py.ml_kem import ML_KEM_512, ML_KEM_768, ML_KEM_1024 | ||
|
||
OIDS = { | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 1): ML_KEM_512, | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 2): ML_KEM_768, | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 3): ML_KEM_1024, | ||
} | ||
|
||
import ecdsa.der as der | ||
|
||
with open(sys.argv[1], "rt") as ek_file: | ||
ek_pem = ek_file.read() | ||
|
||
ek_der = der.unpem(ek_pem) | ||
|
||
s1, empty = der.remove_sequence(ek_der) | ||
if empty != b"": | ||
raise der.UnexpectedDER("Trailing junk after DER public key") | ||
|
||
ver, rest = der.remove_integer(s1) | ||
|
||
if ver != 0: | ||
raise der.UnexpectedDER("Unexpected format version") | ||
|
||
alg_id, rest = der.remove_sequence(rest) | ||
|
||
alg_id, empty = der.remove_object(alg_id) | ||
if alg_id not in OIDS: | ||
raise der.UnexpectedDER(f"Not recognised algoritm OID: {alg_id}") | ||
if empty != b"": | ||
raise der.UnexpectedDER("parameters specified for ML-KEM OID") | ||
|
||
kem = OIDS[alg_id] | ||
|
||
key_der, empty = der.remove_octet_string(rest) | ||
if empty != b"": | ||
raise der.UnexpectedDER("Trailing junk after the key") | ||
|
||
keys, empty = der.remove_octet_string(key_der) | ||
if empty != b"": | ||
raise der.UnexpectedDER("Trailing junk after the key") | ||
|
||
dk_len = 768 * kem.k + 96 | ||
dk, ek = keys[:dk_len], keys[dk_len:] | ||
assert len(ek) == 384 * kem.k + 32 | ||
|
||
with open(sys.argv[3], "rb") as encaps_file: | ||
encaps = encaps_file.read() | ||
|
||
secret = kem.decaps(encaps, dk) | ||
|
||
with open(sys.argv[2], "wb") as secret_file: | ||
secret_file.write(secret) | ||
|
||
print("done") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import sys | ||
|
||
if len(sys.argv) != 4: | ||
raise ValueError(f"Usage: {sys.argv[0]} ek.pem secret.bin ciphertext.bin") | ||
|
||
from kyber_py.ml_kem import ML_KEM_512, ML_KEM_768, ML_KEM_1024 | ||
|
||
OIDS = { | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 1): ML_KEM_512, | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 2): ML_KEM_768, | ||
(1, 3, 6, 1, 4, 1, 22554, 5, 6, 3): ML_KEM_1024, | ||
} | ||
|
||
import ecdsa.der as der | ||
|
||
with open(sys.argv[1], "rt") as ek_file: | ||
ek_pem = ek_file.read() | ||
|
||
ek_der = der.unpem(ek_pem) | ||
|
||
s1, empty = der.remove_sequence(ek_der) | ||
if empty != b"": | ||
raise der.UnexpectedDER("Trailing junk after DER public key") | ||
|
||
alg_id, rem = der.remove_sequence(s1) | ||
|
||
alg_id, rest = der.remove_object(alg_id) | ||
if alg_id not in OIDS: | ||
raise der.UnexpectedDER(f"Not recognised algoritm OID: {alg_id}") | ||
|
||
if rest != b"": | ||
raise der.UnexpectedDER("parameters specified for ML-KEM OID") | ||
|
||
kem = OIDS[alg_id] | ||
|
||
key, empty = der.remove_bitstring(rem, 0) | ||
if empty != b"": | ||
raise der.UnexpectedDER("Trailing junk after the public key bitstring") | ||
|
||
secret, encaps = kem.encaps(key) | ||
|
||
with open(sys.argv[2], "wb") as secret_file: | ||
secret_file.write(secret) | ||
|
||
with open(sys.argv[3], "wb") as encaps_file: | ||
encaps_file.write(encaps) | ||
|
||
print("done") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import sys | ||
|
||
if len(sys.argv) != 4: | ||
raise ValueError(f"Usage: {sys.argv[0]} ML-KEM-(512|768|1024) ek.pem dk.pem") | ||
|
||
if sys.argv[1] == "ML-KEM-512": | ||
from kyber_py.ml_kem.default_parameters import ML_KEM_512 as ML_KEM | ||
oid = (1, 3, 6, 1, 4, 1, 22554, 5, 6, 1) | ||
elif sys.argv[1] == "ML-KEM-768": | ||
from kyber_py.ml_kem.default_parameters import ML_KEM_768 as ML_KEM | ||
oid = (1, 3, 6, 1, 4, 1, 22554, 5, 6, 2) | ||
elif sys.argv[1] == "ML-KEM-1024": | ||
from kyber_py.ml_kem.default_parameters import ML_KEM_1024 as ML_KEM | ||
oid = (1, 3, 6, 1, 4, 1, 22554, 5, 6, 3) | ||
else: | ||
raise ValueError(f"Unrecognised algorithm: {sys.argv[1]}") | ||
|
||
import ecdsa.der as der | ||
|
||
ek, dk = ML_KEM.keygen() | ||
|
||
with open(sys.argv[2], "wb") as ek_file: | ||
encoded = der.encode_sequence( | ||
der.encode_sequence( | ||
der.encode_oid(*oid) | ||
), | ||
der.encode_bitstring(ek, 0), | ||
) | ||
ek_file.write(der.topem(encoded, "PUBLIC KEY")) | ||
|
||
with open(sys.argv[3], "wb") as dk_file: | ||
encoded = der.encode_sequence( | ||
der.encode_integer(0), | ||
der.encode_sequence( | ||
der.encode_oid(*oid) | ||
), | ||
der.encode_octet_string(der.encode_octet_string(dk + ek)), | ||
) | ||
dk_file.write(der.topem(encoded, "PRIVATE KEY")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <stdlib.h> | ||
#include <memory.h> | ||
#include <string.h> | ||
#include <fcntl.h> | ||
#include <openssl/err.h> | ||
#include <openssl/evp.h> | ||
#include <openssl/pem.h> | ||
|
||
void help(char *name) { | ||
printf("Usage: %s -k key.pem -s secret-out.pem -c ciphertext-out.pem\n", | ||
name); | ||
printf("\n"); | ||
printf(" -k file File with the decapsulation key\n"); | ||
printf(" -s file File to write the secret\n"); | ||
printf(" -c file File to read the ciphertext\n"); | ||
} | ||
|
||
int | ||
main(int argc, char** argv) { | ||
EVP_PKEY_CTX *ctx = NULL; | ||
EVP_PKEY *pub_key = NULL; | ||
size_t secretlen = 0, outlen = 0; | ||
unsigned char *out = NULL, *secret = NULL; | ||
char *key_file_name = NULL, *secret_file_name = NULL; | ||
char *ciphertext_file_name = NULL; | ||
int sec_fd = -1, cip_fd = -1; | ||
FILE *fp; | ||
int opt; | ||
int result = 0; | ||
|
||
while ((opt = getopt(argc, argv, "k:s:c:")) != -1 ) { | ||
switch (opt) { | ||
case 'k': | ||
key_file_name = optarg; | ||
break; | ||
case 's': | ||
secret_file_name = optarg; | ||
break; | ||
case 'c': | ||
ciphertext_file_name = optarg; | ||
break; | ||
default: | ||
fprintf(stderr, "Unknown option: %c\n", opt); | ||
help(argv[0]); | ||
exit(1); | ||
break; | ||
} | ||
} | ||
|
||
if (key_file_name == NULL || secret_file_name == NULL || | ||
ciphertext_file_name == NULL) { | ||
fprintf(stderr, "All options must be specified!\n"); | ||
help(argv[0]); | ||
exit(1); | ||
} | ||
|
||
if ((sec_fd = open(secret_file_name, O_WRONLY|O_TRUNC|O_CREAT, 0666)) | ||
== -1){ | ||
fprintf(stderr, "can't open output file: %s\n", secret_file_name); | ||
goto err; | ||
} | ||
|
||
if ((cip_fd = open(ciphertext_file_name, O_RDONLY)) == -1) { | ||
fprintf(stderr, "Can't open output file: %s\n", ciphertext_file_name); | ||
goto err; | ||
} | ||
|
||
fp = fopen(key_file_name, "r"); | ||
if (!fp) { | ||
fprintf(stderr, "Can't open key file: %s\n", key_file_name); | ||
goto err; | ||
} | ||
|
||
if ((pub_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) { | ||
//if ((pub_key = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
fprintf(stderr, "Can't read parse private key\n"); | ||
goto err; | ||
} | ||
|
||
if (fclose(fp) != 0) { | ||
fprintf(stderr, "can't close key file\n"); | ||
goto err; | ||
} | ||
fp = NULL; | ||
|
||
ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pub_key, NULL); | ||
if (ctx == NULL) { | ||
fprintf(stderr, "Can't init key context\n"); | ||
goto err; | ||
} | ||
if (EVP_PKEY_decapsulate_init(ctx, NULL) <= 0) { | ||
fprintf(stderr, "Can't init encapsulation\n"); | ||
goto err; | ||
} | ||
|
||
secretlen = 4096; | ||
secret = OPENSSL_malloc(secretlen); | ||
secretlen = read(cip_fd, secret, secretlen); | ||
if (secretlen <= 0) { | ||
fprintf(stderr, "Can't read ciphertext\n"); | ||
goto err; | ||
} | ||
|
||
/* Determine buffer length */ | ||
if (EVP_PKEY_decapsulate(ctx, NULL, &outlen, secret, secretlen) <= 0) { | ||
fprintf(stderr, "Can't fetch memory size\n"); | ||
} | ||
|
||
out = OPENSSL_malloc(outlen); | ||
if (out == NULL || secret == NULL) { | ||
fprintf(stderr, "memory allocation failure\n"); | ||
goto err; | ||
} | ||
|
||
/* | ||
* The decapsulated 'out' can be used as key material. | ||
*/ | ||
if (EVP_PKEY_decapsulate(ctx, out, &outlen, secret, secretlen) <= 0) { | ||
fprintf(stderr, "decapsulation failure\n"); | ||
goto err; | ||
} | ||
|
||
if (write(sec_fd, out, outlen) <= 0) { | ||
fprintf(stderr, "Error writing secret\n"); | ||
goto err; | ||
} | ||
|
||
printf("done\n"); | ||
|
||
goto out; | ||
|
||
err: | ||
result = 1; | ||
fprintf(stderr, "operation failed\n"); | ||
ERR_print_errors_fp(stderr); | ||
|
||
out: | ||
if (sec_fd >= 0) | ||
close(sec_fd); | ||
if (cip_fd >= 0) | ||
close(cip_fd); | ||
if (fp) | ||
fclose(fp); | ||
if (out) | ||
OPENSSL_free(out); | ||
if (secret) | ||
OPENSSL_free(secret); | ||
if (ctx) | ||
EVP_PKEY_CTX_free(ctx); | ||
if (pub_key) | ||
EVP_PKEY_free(pub_key); | ||
|
||
return result; | ||
} |
Oops, something went wrong.