1#' Signatures
2#'
3#' Sign and verify a message digest. RSA supports both MD5 and SHA signatures
4#' whereas DSA and EC keys only support SHA. ED25591 can sign any payload so you can
5#' set `hash` to `NULL` to sign the raw input data.
6#'
7#' The \code{ecdsa_parse} and \code{ecdsa_write} functions convert (EC)DSA signatures
8#' between the conventional DER format and the raw \code{(r,s)} bignum pair. Most
9#' users won't need this, it is mostly here to support the JWT format (which does not
10#' use DER).
11#'
12#' @export
13#' @rdname signatures
14#' @param data raw data vector or file path for message to be signed.
15#' If \code{hash == NULL} then \code{data} must be a hash string or raw vector.
16#' @param hash the digest function to use. Must be one of \code{\link{md5}},
17#' \code{\link{sha1}}, \code{\link{sha256}}, \code{\link{sha512}} or \code{NULL}.
18#' @param key private key or file path. See \code{\link{read_key}}.
19#' @param pubkey public key or file path. See \code{\link{read_pubkey}}.
20#' @param sig raw vector or file path for the signature data.
21#' @param password string or a function to read protected keys. See \code{\link{read_key}}.
22#' @examples # Generate a keypair
23#' key <- rsa_keygen()
24#' pubkey <- key$pubkey
25#'
26#' # Sign a file
27#' data <- system.file("DESCRIPTION")
28#' sig <- signature_create(data, key = key)
29#' stopifnot(signature_verify(data, sig, pubkey = pubkey))
30#'
31#' # Sign raw data
32#' data <- serialize(iris, NULL)
33#' sig <- signature_create(data, sha256, key = key)
34#' stopifnot(signature_verify(data, sig, sha256, pubkey = pubkey))
35#'
36#' # Sign a hash
37#' md <- md5(data)
38#' sig <- signature_create(md, hash = NULL, key = key)
39#' stopifnot(signature_verify(md, sig, hash = NULL, pubkey = pubkey))
40signature_create <- function(data, hash = sha1, key = my_key(), password = askpass){
41  data <- path_or_raw(data)
42  sk <- read_key(key, password = password)
43  md <- if(is.null(hash)) parse_hash(data) else hash(data)
44  if(inherits(sk, "ed25519"))
45    return(data_sign(md, sk))
46  if(!is.raw(md) || !(length(md) %in% c(16, 20, 28, 32, 48, 64)))
47    stop("data must be md5, sha1, or sha2 digest")
48  hash_sign(md, sk)
49}
50
51#' @export
52#' @rdname signatures
53signature_verify <- function(data, sig, hash = sha1, pubkey = my_pubkey()){
54  data <- path_or_raw(data)
55  sig <- path_or_raw(sig)
56  pk <- read_pubkey(pubkey)
57  md <- if(is.null(hash)) parse_hash(data) else hash(data)
58  if(inherits(pk, "ed25519"))
59    return(data_verify(md, sig, pk))
60  if(!is.raw(md) || !(length(md) %in% c(16, 20, 28, 32, 48, 64)))
61    stop("data must be md5, sha1, or sha2 digest")
62  hash_verify(md, sig, pk)
63}
64
65#' @export
66#' @rdname signatures
67#' @useDynLib openssl R_parse_ecdsa
68#' @examples #
69#' # ECDSA example
70#' data <- serialize(iris, NULL)
71#' key <- ec_keygen()
72#' pubkey <- key$pubkey
73#' sig <- signature_create(data, sha256, key = key)
74#' stopifnot(signature_verify(data, sig, sha256, pubkey = pubkey))
75#'
76#' # Convert signature to (r, s) parameters and then back
77#' params <- ecdsa_parse(sig)
78#' out <- ecdsa_write(params$r, params$s)
79#' identical(sig, out)
80ecdsa_parse <- function(sig){
81  if(length(sig) > 150)
82    warning("You can only parse DSA and ECDSA signatures. This looks like an RSA signature.")
83  .Call(R_parse_ecdsa, sig)
84}
85
86#' @export
87#' @rdname signatures
88#' @useDynLib openssl R_write_ecdsa
89#' @param r bignum value for r parameter
90#' @param s bignum value for s parameter
91ecdsa_write <- function(r, s){
92  stopifnot(is.raw(r), is.raw(s))
93  class(r) <- "bignum"
94  class(s) <- "bignum"
95  .Call(R_write_ecdsa, r, s)
96}
97
98#' @useDynLib openssl R_hash_sign
99hash_sign <- function(hash, key){
100  .Call(R_hash_sign, hash, key)
101}
102
103#' @useDynLib openssl R_hash_verify
104hash_verify <- function(hash, sig, pubkey){
105  .Call(R_hash_verify, hash, sig, pubkey)
106}
107