1#' Curve25519
2#'
3#' Curve25519 is a recently added low-level algorithm that can be used both for
4#' diffie-hellman (called X25519) and for signatures (called ED25519). Note that
5#' these functions are only available when building against version 1.1.1 or
6#' newer of the openssl library. The same functions are also available in the
7#' sodium R package.
8#'
9#' @export
10#' @name curve25519
11#' @rdname curve25519
12#' @param x a 32 byte raw vector with (pub)key data
13#' @examples # Generate a keypair
14#' if(openssl_config()$x25519){
15#' key <- ed25519_keygen()
16#' pubkey <- as.list(key)$pubkey
17#'
18#' # Sign message
19#' msg <- serialize(iris, NULL)
20#' sig <- ed25519_sign(msg, key)
21#'
22#' # Verify the signature
23#' ed25519_verify(msg, sig, pubkey)
24#'
25#' # Diffie Hellman example:
26#' key1 <- x25519_keygen()
27#' key2 <- x25519_keygen()
28#'
29#' # Both parties can derive the same secret
30#' x25519_diffie_hellman(key1, key2$pubkey)
31#' x25519_diffie_hellman(key2, key1$pubkey)
32#'
33#' # Import/export sodium keys
34#' rawkey <- sodium::sig_keygen()
35#' rawpubkey <- sodium::sig_pubkey(rawkey)
36#' key <- read_ed25519_key(rawkey)
37#' pubkey <- read_ed25519_pubkey(rawpubkey)
38#'
39#' # To get the raw key data back for use in sodium
40#' as.list(key)$data
41#' as.list(pubkey)$data
42#' }
43read_ed25519_key <- function(x){
44  stopifnot(is.raw(x))
45  if(length(x) == 64)
46    x <- utils::head(x, 32L)
47  stopifnot(length(x) == 32)
48  structure(read_raw_key_ed25519(x), class = c("key", "ed25519"))
49}
50
51#' @export
52#' @rdname curve25519
53read_ed25519_pubkey <- function(x){
54  stopifnot(is.raw(x))
55  stopifnot(length(x) == 32)
56  structure(read_raw_pubkey_ed25519(x), class = c("pubkey", "ed25519"))
57}
58
59#' @export
60#' @rdname curve25519
61read_x25519_key <- function(x){
62  stopifnot(is.raw(x))
63  if(length(x) == 64)
64    x <- utils::head(x, 32L)
65  stopifnot(length(x) == 32)
66  structure(read_raw_key_x25519(x), class = c("key", "x25519"))
67}
68
69#' @export
70#' @rdname curve25519
71read_x25519_pubkey <- function(x){
72  stopifnot(is.raw(x))
73  stopifnot(length(x) == 32)
74  structure(read_raw_pubkey_x25519(x), class = c("pubkey", "x25519"))
75}
76
77#' @export
78#' @rdname curve25519
79#' @param key private key as returned by \code{read_ed25519_key} or \code{ed25519_keygen}
80ed25519_sign <- function(data, key){
81  stopifnot(is.raw(data))
82  key <- read_key(key)
83  stopifnot(inherits(key, 'ed25519'))
84  data_sign(data, key)
85}
86
87#' @export
88#' @rdname curve25519
89#' @param data raw vector with data to sign or verify
90#' @param sig raw vector of length 64 with signature as returned by \code{ed25519_sign}
91#' @param pubkey public key as returned by \code{read_ed25519_pubkey} or \code{key$pubkey}
92ed25519_verify <- function(data, sig, pubkey){
93  stopifnot(is.raw(data))
94  stopifnot(is.raw(sig))
95  if(length(sig) != 64)
96    stop("Signature must have length 64")
97  pubkey <- read_pubkey(pubkey)
98  stopifnot(inherits(pubkey, 'ed25519'))
99  data_verify(data, sig, pubkey)
100}
101
102#' @export
103#' @rdname curve25519
104x25519_diffie_hellman <- function(key, pubkey){
105  key <- read_key(key)
106  pubkey <- read_pubkey(pubkey)
107  stopifnot(inherits(key, 'x25519'))
108  stopifnot(inherits(pubkey, 'x25519'))
109  ec_dh(key, pubkey)
110}
111
112#' @useDynLib openssl R_read_raw_key_ed25519
113read_raw_key_ed25519 <- function(x){
114  .Call(R_read_raw_key_ed25519, x)
115}
116
117#' @useDynLib openssl R_read_raw_pubkey_ed25519
118read_raw_pubkey_ed25519 <- function(x){
119  .Call(R_read_raw_pubkey_ed25519, x)
120}
121
122#' @useDynLib openssl R_read_raw_key_x25519
123read_raw_key_x25519 <- function(x){
124  .Call(R_read_raw_key_x25519, x)
125}
126
127#' @useDynLib openssl R_read_raw_pubkey_x25519
128read_raw_pubkey_x25519 <- function(x){
129  .Call(R_read_raw_pubkey_x25519, x)
130}
131
132#' @useDynLib openssl R_write_raw_key
133write_raw_key <- function(x){
134  .Call(R_write_raw_key, x)
135}
136
137#' @useDynLib openssl R_write_raw_pubkey
138write_raw_pubkey <- function(x){
139  .Call(R_write_raw_pubkey, x)
140}
141
142#' @useDynLib openssl R_data_sign
143data_sign <- function(data, key){
144  .Call(R_data_sign, data, key)
145}
146
147#' @useDynLib openssl R_data_verify
148data_verify <- function(data, sig, pubkey){
149  .Call(R_data_verify, data, sig, pubkey)
150}
151