-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat_keywriter' into develop
- Loading branch information
Showing
9 changed files
with
483 additions
and
4 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
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
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 |
---|---|---|
@@ -1,9 +1,14 @@ | ||
# pqcrypto (development version) | ||
|
||
* Internals: | ||
- Some changes to classes, new tests, lib compilation, ... | ||
- Change data types from integer to raw. | ||
##### New Features | ||
- Specialized `print()` for pqcrypto_* objects | ||
- Add new signing algorithm: Sphincs+ | ||
- Add `write_key()` and `open_key()` to key saving and retrieval | ||
|
||
##### Internals | ||
- Some changes to classes, new tests, lib compilation, ... | ||
- Change data types from integer to raw | ||
|
||
# pqcrypto 0.1.0 | ||
|
||
* Initial public version. | ||
- Initial public version. |
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,62 @@ | ||
|
||
#' Key Management - Open | ||
#' | ||
#' Opens a private key or a public key file generated by `write_key()`. | ||
#' | ||
#' @param file_name The file containing a key to be opened. | ||
#' @param password If the `file_name`contains an encrypted private key, the decryption password. | ||
#' | ||
#' @return The public or private key. | ||
#' | ||
#' @export | ||
#' | ||
#' @examples | ||
#' key <- keygen_kyber() | ||
#' path <- tempdir() | ||
#' write_key(key$private, path, "myPassword") | ||
#' prv <- open_key(paste0(path, "/keypair"), "myPassword") | ||
#' | ||
#' identical(key$private, prv) | ||
#' | ||
open_key <- function(file_name, password = NULL) { | ||
|
||
b64_to_raw <- function(txt) { | ||
if (requireNamespace("openssl", quietly = TRUE)) { | ||
key <- openssl::base64_decode(txt) | ||
} else if (requireNamespace("base64enc", quietly = TRUE)) { | ||
key <- base64enc::base64decode(txt) | ||
} else { | ||
pq_msg(c(x="Unable to read the keys if openssl or base64enc packages are not present.")) | ||
return(NULL) | ||
} | ||
invisible(key) | ||
} | ||
|
||
if(!file.exists(file_name)) { | ||
pq_stop(c(x = "Invalid 'file_name'.")) | ||
} | ||
keydata <- readLines(file_name) | ||
base64text <- paste0(keydata[2:(length(keydata)-1)], collapse = "\n") | ||
|
||
if (keydata[1] %in% c("-----BEGIN PUBLIC KEY-----", "-----BEGIN PRIVATE KEY-----")) { | ||
raw_key <- b64_to_raw(base64text) | ||
|
||
} else if (keydata[1] == "-----BEGIN ENCRYPTED PRIVATE KEY-----") { | ||
if (!is.null(password)) { | ||
if (requireNamespace("openssl", quietly = TRUE)) { | ||
raw_data <- unserialize(b64_to_raw(base64text)) | ||
raw_key <- openssl::aes_cbc_decrypt(raw_data, openssl::sha256(charToRaw(password))) | ||
} else { | ||
pq_msg(c(x="Reading encrypted private key files requires openssl package.")) | ||
return(NULL) | ||
} | ||
} else { | ||
pq_stop(c(x="Reading encrypted private key files requires `password` argument to be provided.")) | ||
} | ||
} else { | ||
pq_stop(c(x="File does not look like a key file.", | ||
i="Make sure the `file_name` argument points to a file created by `write_key()`.")) | ||
} | ||
|
||
unserialize(raw_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,120 @@ | ||
|
||
#' Key Management - Save | ||
#' | ||
#' Saves a key-pair, a private key or a public key as a text file. | ||
#' **NOTE**: While the text file resembles a PEM encoded key, current implementation is not strictly | ||
#' following RFC7468 (Textual Encodings of PKIX, PKCS, and CMS Structures), RFC5280 (Internet X.509 | ||
#' Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile) and RFC5958 | ||
#' (Asymmetric Key Packages). | ||
#' | ||
#' @param key A key-pair produced by `keygen_kyber()`, `keygen_dilithium()` or | ||
#' `keygen_sphincs()`, or a private key or public key belonging to such a key-pair. | ||
#' @param path A path where the text file(s) containing the key(s) should be saved. | ||
#' Defaults to the temporary directory. If NULL, the resulting encoded key is printed to the | ||
#' console. | ||
#' @param password A password to be used for private key encryption. If not provided, which is | ||
#' **not advisable** when saving private keys (or the full key-pair) because the private key will | ||
#' not be encrypted which is **potentially unsafe**. | ||
#' | ||
#' @return Invisibly the encoded key. Saves it to a file or displays it on the console. | ||
#' | ||
#' @export | ||
#' | ||
#' @examples | ||
#' key <- keygen_sphincs() | ||
#' write_key(key$public, NULL) # NULL used here to force console output instead of file saving | ||
#' | ||
write_key <- function(key, path = tempdir(), password = NULL) { | ||
|
||
raw_to_b64 <- function(k) { | ||
if (requireNamespace("openssl", quietly = TRUE)) { | ||
base64text <- openssl::base64_encode(serialize(k, NULL), TRUE) | ||
} else if (requireNamespace("base64enc", quietly = TRUE)) { | ||
base64text <- paste0(base64enc::base64encode(serialize(k, NULL), 64, "\n"), "\n") | ||
} else { | ||
pq_msg(c(x="Unable to write keys to file if openssl or base64enc packages are not present.")) | ||
return(NULL) | ||
} | ||
invisible(base64text) | ||
} | ||
|
||
public <- function(k) { | ||
paste0("-----BEGIN PUBLIC KEY-----\n", | ||
raw_to_b64(k), | ||
"-----END PUBLIC KEY-----\n") | ||
} | ||
|
||
private <- function(k) { | ||
paste0("-----BEGIN PRIVATE KEY-----\n", | ||
raw_to_b64(k), | ||
"-----END PRIVATE KEY-----\n") | ||
} | ||
|
||
private_enc <- function(k, password) { | ||
if (requireNamespace("openssl", quietly = TRUE)) { | ||
enc <- openssl::aes_cbc_encrypt(serialize(k, NULL), | ||
openssl::sha256(charToRaw(password))) | ||
} else { | ||
pq_msg(c(x="Private key encryption requires openssl package.")) | ||
return(NULL) | ||
} | ||
paste0("-----BEGIN ENCRYPTED PRIVATE KEY-----\n", | ||
raw_to_b64(enc), | ||
"-----END ENCRYPTED PRIVATE KEY-----\n") | ||
} | ||
|
||
if(!is.null(path) && !dir.exists(path)) { | ||
pq_stop(c(x = "Unable to find the specified 'path' to write into.")) | ||
} | ||
|
||
if (inherits(key, "pqcrypto_keypair")) { | ||
if (!is.null(password)) { | ||
cert_prv <- private_enc(key$private, as.character(password)) | ||
} else { | ||
cert_prv <- private(key$private) | ||
} | ||
cert_pub <- public(key$public) | ||
|
||
if (is.null(path)) { | ||
cat(cert_prv, "\n", cert_pub, sep = "") | ||
} else { | ||
ff <- file(paste0(path, "/keypair"), "wt") | ||
cat(cert_prv, file = ff) | ||
close(ff) | ||
ff <- file(paste0(path, "/keypair.pub"), "wt") | ||
cat(cert_pub, file = ff) | ||
close(ff) | ||
} | ||
|
||
} else if (inherits(key, "pqcrypto_private_key")) { | ||
if (!is.null(password)) { | ||
cert_prv <- private_enc(key, password) | ||
} else { | ||
cert_prv <- private(key) | ||
} | ||
if (is.null(path)) { | ||
cat(cert_prv) | ||
} else { | ||
ff <- file(paste0(path, "/keypair"), "wt") | ||
cat(cert_prv, file = ff) | ||
close(ff) | ||
} | ||
invisible(cert_prv) | ||
|
||
} else if (inherits(key, "pqcrypto_public_key")) { | ||
cert_pub <- public(key) | ||
if (is.null(path)) { | ||
cat(cert_pub) | ||
} else { | ||
ff <- file(paste0(path, "/keypair.pub"), "wt") | ||
cat(cert_pub, file = ff) | ||
close(ff) | ||
} | ||
invisible(cert_pub) | ||
|
||
} else { | ||
pq_stop("Invalid object type.") | ||
} | ||
|
||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,97 @@ | ||
test_that("Read Kyber key-pair", { | ||
|
||
key <- keygen_kyber() | ||
path <- tempdir() | ||
|
||
write_key(key, path) | ||
prv <- open_key(paste0(path, "/keypair")) | ||
pub <- open_key(paste0(path, "/keypair.pub")) | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
write_key(key, path, "mypass") | ||
prv <- open_key(paste0(path, "/keypair"), "mypass") | ||
pub <- open_key(paste0(path, "/keypair.pub"), "mypass") | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
|
||
expect_error(open_key(paste0(path, "/keypair"))) | ||
expect_error(open_key(paste0(path, "/keypair"), "notmypass")) | ||
expect_error(open_key("/invalid_path/keypair", "mypass")) | ||
expect_error(open_key("/invalid_path/keypair.pub", "mypass")) | ||
|
||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
}) | ||
|
||
test_that("Read Dilithium key-pair", { | ||
|
||
key <- keygen_dilithium() | ||
path <- tempdir() | ||
|
||
write_key(key, path) | ||
prv <- open_key(paste0(path, "/keypair")) | ||
pub <- open_key(paste0(path, "/keypair.pub")) | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
write_key(key, path, "mypass") | ||
prv <- open_key(paste0(path, "/keypair"), "mypass") | ||
pub <- open_key(paste0(path, "/keypair.pub"), "mypass") | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
|
||
expect_error(open_key(paste0(path, "/keypair"))) | ||
expect_error(open_key(paste0(path, "/keypair"), "notmypass")) | ||
expect_error(open_key("/invalid_path/keypair", "mypass")) | ||
expect_error(open_key("/invalid_path/keypair.pub", "mypass")) | ||
|
||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
}) | ||
|
||
test_that("Read Sphincs+ key-pair", { | ||
|
||
key <- keygen_sphincs() | ||
path <- tempdir() | ||
|
||
write_key(key, path) | ||
prv <- open_key(paste0(path, "/keypair")) | ||
pub <- open_key(paste0(path, "/keypair.pub")) | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
write_key(key, path, "mypass") | ||
prv <- open_key(paste0(path, "/keypair"), "mypass") | ||
pub <- open_key(paste0(path, "/keypair.pub"), "mypass") | ||
expect_identical(key$private, prv) | ||
expect_identical(key$public, pub) | ||
|
||
expect_error(open_key(paste0(path, "/keypair"))) | ||
expect_error(open_key(paste0(path, "/keypair"), "notmypass")) | ||
expect_error(open_key("/invalid_path/keypair", "mypass")) | ||
expect_error(open_key("/invalid_path/keypair.pub", "mypass")) | ||
|
||
unlink(paste0(path, "/keypair")) | ||
unlink(paste0(path, "/keypair.pub")) | ||
|
||
}) | ||
|
||
test_that("Fails on bad file", { | ||
|
||
file <- tempfile() | ||
writeLines("qwerty", file(file)) | ||
|
||
expect_error(open_key(file)) | ||
|
||
unlink(file) | ||
|
||
}) |
Oops, something went wrong.