diff options
| -rw-r--r-- | guix/pk-crypto.scm | 83 | ||||
| -rw-r--r-- | tests/pk-crypto.scm | 42 |
2 files changed, 124 insertions, 1 deletions
diff --git a/guix/pk-crypto.scm b/guix/pk-crypto.scm index 9d093b34b0e..d8fbb6f85b4 100644 --- a/guix/pk-crypto.scm +++ b/guix/pk-crypto.scm | |||
| @@ -18,7 +18,9 @@ | |||
| 18 | 18 | ||
| 19 | (define-module (guix pk-crypto) | 19 | (define-module (guix pk-crypto) |
| 20 | #:use-module (guix config) | 20 | #:use-module (guix config) |
| 21 | #:use-module ((guix utils) #:select (bytevector->base16-string)) | 21 | #:use-module ((guix utils) |
| 22 | #:select (bytevector->base16-string | ||
| 23 | base16-string->bytevector)) | ||
| 22 | #:use-module (system foreign) | 24 | #:use-module (system foreign) |
| 23 | #:use-module (rnrs bytevectors) | 25 | #:use-module (rnrs bytevectors) |
| 24 | #:use-module (ice-9 match) | 26 | #:use-module (ice-9 match) |
| @@ -26,7 +28,12 @@ | |||
| 26 | string->gcry-sexp | 28 | string->gcry-sexp |
| 27 | gcry-sexp->string | 29 | gcry-sexp->string |
| 28 | number->gcry-sexp | 30 | number->gcry-sexp |
| 31 | gcry-sexp-car | ||
| 32 | gcry-sexp-cdr | ||
| 33 | gcry-sexp-nth | ||
| 34 | gcry-sexp-nth-data | ||
| 29 | bytevector->hash-data | 35 | bytevector->hash-data |
| 36 | hash-data->bytevector | ||
| 30 | sign | 37 | sign |
| 31 | verify | 38 | verify |
| 32 | generate-key | 39 | generate-key |
| @@ -105,6 +112,61 @@ | |||
| 105 | (loop (* len 2)) | 112 | (loop (* len 2)) |
| 106 | (pointer->string buf size "ISO-8859-1"))))))) | 113 | (pointer->string buf size "ISO-8859-1"))))))) |
| 107 | 114 | ||
| 115 | (define gcry-sexp-car | ||
| 116 | (let* ((ptr (libgcrypt-func "gcry_sexp_car")) | ||
| 117 | (proc (pointer->procedure '* ptr '(*)))) | ||
| 118 | (lambda (lst) | ||
| 119 | "Return the first element of LST, an sexp, if that element is a list; | ||
| 120 | return #f if LST or its first element is not a list (this is different from | ||
| 121 | the usual Lisp 'car'.)" | ||
| 122 | (let ((result (proc (gcry-sexp->pointer lst)))) | ||
| 123 | (if (null-pointer? result) | ||
| 124 | #f | ||
| 125 | (pointer->gcry-sexp result)))))) | ||
| 126 | |||
| 127 | (define gcry-sexp-cdr | ||
| 128 | (let* ((ptr (libgcrypt-func "gcry_sexp_cdr")) | ||
| 129 | (proc (pointer->procedure '* ptr '(*)))) | ||
| 130 | (lambda (lst) | ||
| 131 | "Return the tail of LST, an sexp, or #f if LST is not a list." | ||
| 132 | (let ((result (proc (gcry-sexp->pointer lst)))) | ||
| 133 | (if (null-pointer? result) | ||
| 134 | #f | ||
| 135 | (pointer->gcry-sexp result)))))) | ||
| 136 | |||
| 137 | (define gcry-sexp-nth | ||
| 138 | (let* ((ptr (libgcrypt-func "gcry_sexp_nth")) | ||
| 139 | (proc (pointer->procedure '* ptr `(* ,int)))) | ||
| 140 | (lambda (lst index) | ||
| 141 | "Return the INDEXth nested element of LST, an s-expression. Return #f | ||
| 142 | if that element does not exist, or if it's an atom. (Note: this is obviously | ||
| 143 | different from Scheme's 'list-ref'.)" | ||
| 144 | (let ((result (proc (gcry-sexp->pointer lst) index))) | ||
| 145 | (if (null-pointer? result) | ||
| 146 | #f | ||
| 147 | (pointer->gcry-sexp result)))))) | ||
| 148 | |||
| 149 | (define (dereference-size_t p) | ||
| 150 | "Return the size_t value pointed to by P." | ||
| 151 | (bytevector-uint-ref (pointer->bytevector p (sizeof size_t)) | ||
| 152 | 0 (native-endianness) | ||
| 153 | (sizeof size_t))) | ||
| 154 | |||
| 155 | (define gcry-sexp-nth-data | ||
| 156 | (let* ((ptr (libgcrypt-func "gcry_sexp_nth_data")) | ||
| 157 | (proc (pointer->procedure '* ptr `(* ,int *)))) | ||
| 158 | (lambda (lst index) | ||
| 159 | "Return as a string the INDEXth data element (atom) of LST, an | ||
| 160 | s-expression. Return #f if that element does not exist, or if it's a list. | ||
| 161 | Note that the result is a Scheme string, but depending on LST, it may need to | ||
| 162 | be interpreted in the sense of a C string---i.e., as a series of octets." | ||
| 163 | (let* ((size* (bytevector->pointer (make-bytevector (sizeof '*)))) | ||
| 164 | (result (proc (gcry-sexp->pointer lst) index size*))) | ||
| 165 | (if (null-pointer? result) | ||
| 166 | #f | ||
| 167 | (pointer->string result (dereference-size_t size*) | ||
| 168 | "ISO-8859-1")))))) | ||
| 169 | |||
| 108 | (define (number->gcry-sexp number) | 170 | (define (number->gcry-sexp number) |
| 109 | "Return an s-expression representing NUMBER." | 171 | "Return an s-expression representing NUMBER." |
| 110 | (string->gcry-sexp (string-append "#" (number->string number 16) "#"))) | 172 | (string->gcry-sexp (string-append "#" (number->string number 16) "#"))) |
| @@ -117,6 +179,25 @@ for use as the data for 'sign'." | |||
| 117 | hash-algo | 179 | hash-algo |
| 118 | (bytevector->base16-string bv)))) | 180 | (bytevector->base16-string bv)))) |
| 119 | 181 | ||
| 182 | (define (latin1-string->bytevector str) | ||
| 183 | "Return a bytevector representing STR." | ||
| 184 | ;; XXX: In Guile 2.0.9 and later, we would use 'string->bytevector' for | ||
| 185 | ;; that. | ||
| 186 | (let ((bytes (map char->integer (string->list str)))) | ||
| 187 | (u8-list->bytevector bytes))) | ||
| 188 | |||
| 189 | (define (hash-data->bytevector data) | ||
| 190 | "Return two values: the hash algorithm (a string) and the hash value (a | ||
| 191 | bytevector) extract from DATA, an sexp as returned by 'bytevector->hash-data'. | ||
| 192 | Return #f if DATA does not conform." | ||
| 193 | (let ((hash (find-sexp-token data 'hash))) | ||
| 194 | (if hash | ||
| 195 | (let ((algo (gcry-sexp-nth-data hash 1)) | ||
| 196 | (value (gcry-sexp-nth-data hash 2))) | ||
| 197 | (values (latin1-string->bytevector value) | ||
| 198 | algo)) | ||
| 199 | (values #f #f)))) | ||
| 200 | |||
| 120 | (define sign | 201 | (define sign |
| 121 | (let* ((ptr (libgcrypt-func "gcry_pk_sign")) | 202 | (let* ((ptr (libgcrypt-func "gcry_pk_sign")) |
| 122 | (proc (pointer->procedure int ptr '(* * *)))) | 203 | (proc (pointer->procedure int ptr '(* * *)))) |
diff --git a/tests/pk-crypto.scm b/tests/pk-crypto.scm index 1acce13f0a2..7c54e729ad5 100644 --- a/tests/pk-crypto.scm +++ b/tests/pk-crypto.scm | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | #:use-module (guix utils) | 21 | #:use-module (guix utils) |
| 22 | #:use-module (guix hash) | 22 | #:use-module (guix hash) |
| 23 | #:use-module (srfi srfi-1) | 23 | #:use-module (srfi srfi-1) |
| 24 | #:use-module (srfi srfi-11) | ||
| 25 | #:use-module (srfi srfi-26) | ||
| 24 | #:use-module (srfi srfi-64) | 26 | #:use-module (srfi srfi-64) |
| 25 | #:use-module (rnrs bytevectors) | 27 | #:use-module (rnrs bytevectors) |
| 26 | #:use-module (rnrs io ports) | 28 | #:use-module (rnrs io ports) |
| @@ -75,6 +77,38 @@ | |||
| 75 | 77 | ||
| 76 | (gc) | 78 | (gc) |
| 77 | 79 | ||
| 80 | (test-equal "gcry-sexp-car + cdr" | ||
| 81 | '("(b \n (c xyz)\n )") | ||
| 82 | (let ((lst (string->gcry-sexp "(a (b (c xyz)))"))) | ||
| 83 | (map (lambda (sexp) | ||
| 84 | (and sexp (string-trim-both (gcry-sexp->string sexp)))) | ||
| 85 | ;; Note: 'car' returns #f when the first element is an atom. | ||
| 86 | (list (gcry-sexp-car (gcry-sexp-cdr lst)))))) | ||
| 87 | |||
| 88 | (gc) | ||
| 89 | |||
| 90 | (test-equal "gcry-sexp-nth" | ||
| 91 | '(#f "(b pqr)" "(c \"456\")" "(d xyz)" #f #f) | ||
| 92 | (let ((lst (string->gcry-sexp "(a (b 3:pqr) (c 3:456) (d 3:xyz))"))) | ||
| 93 | (map (lambda (sexp) | ||
| 94 | (and sexp (string-trim-both (gcry-sexp->string sexp)))) | ||
| 95 | (unfold (cut > <> 5) | ||
| 96 | (cut gcry-sexp-nth lst <>) | ||
| 97 | 1+ | ||
| 98 | 0)))) | ||
| 99 | |||
| 100 | (gc) | ||
| 101 | |||
| 102 | (test-equal "gcry-sexp-nth-data" | ||
| 103 | '("Name" "Otto" "Meier" #f #f #f) | ||
| 104 | (let ((lst (string->gcry-sexp "(Name Otto Meier (address Burgplatz))"))) | ||
| 105 | (unfold (cut > <> 5) | ||
| 106 | (cut gcry-sexp-nth-data lst <>) | ||
| 107 | 1+ | ||
| 108 | 0))) | ||
| 109 | |||
| 110 | (gc) | ||
| 111 | |||
| 78 | ;; XXX: The test below is typically too long as it needs to gather enough entropy. | 112 | ;; XXX: The test below is typically too long as it needs to gather enough entropy. |
| 79 | 113 | ||
| 80 | ;; (test-assert "generate-key" | 114 | ;; (test-assert "generate-key" |
| @@ -85,6 +119,14 @@ | |||
| 85 | ;; (find-sexp-token key 'public-key) | 119 | ;; (find-sexp-token key 'public-key) |
| 86 | ;; (find-sexp-token key 'private-key)))) | 120 | ;; (find-sexp-token key 'private-key)))) |
| 87 | 121 | ||
| 122 | (test-assert "bytevector->hash-data->bytevector" | ||
| 123 | (let* ((bv (sha256 (string->utf8 "Hello, world."))) | ||
| 124 | (data (bytevector->hash-data bv "sha256"))) | ||
| 125 | (and (gcry-sexp? data) | ||
| 126 | (let-values (((value algo) (hash-data->bytevector data))) | ||
| 127 | (and (string=? algo "sha256") | ||
| 128 | (bytevector=? value bv)))))) | ||
| 129 | |||
| 88 | (test-assert "sign + verify" | 130 | (test-assert "sign + verify" |
| 89 | (let* ((pair (string->gcry-sexp %key-pair)) | 131 | (let* ((pair (string->gcry-sexp %key-pair)) |
| 90 | (secret (find-sexp-token pair 'private-key)) | 132 | (secret (find-sexp-token pair 'private-key)) |
