pk-crypto: Use RFC6979 when signing with an ECC or DSA key.
* guix/pk-crypto.scm (bytevector->hash-data): Add #:key-type parameter. Use the 'pkcs1' flag when KEY-TYPE is 'rsa', and 'rfc6979' when KEY-TYPE is 'ecc' or 'dsa'. (key-type): New procedure. * guix/scripts/authenticate.scm (read-hash-data): Add 'key-type' parameter. Pass it to 'bytevector->hash-data'. Adjust caller accordingly. * tests/pk-crypto.scm (%ecc-key-pair): New variable. ("key-type"): New test. ("sign + verify"): Pass #:key-type to 'bytevector->hash-data'. ("sign + verify, Ed25519"): New test.
This commit is contained in:
parent
0f4139e97e
commit
32a1eb8025
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
canonical-sexp-list?
|
canonical-sexp-list?
|
||||||
bytevector->hash-data
|
bytevector->hash-data
|
||||||
hash-data->bytevector
|
hash-data->bytevector
|
||||||
|
key-type
|
||||||
sign
|
sign
|
||||||
verify
|
verify
|
||||||
generate-key
|
generate-key
|
||||||
|
@ -232,15 +233,31 @@ Return #f if that element does not exist, or if it's a list."
|
||||||
"Return an s-expression representing NUMBER."
|
"Return an s-expression representing NUMBER."
|
||||||
(string->canonical-sexp (string-append "#" (number->string number 16) "#")))
|
(string->canonical-sexp (string-append "#" (number->string number 16) "#")))
|
||||||
|
|
||||||
(define* (bytevector->hash-data bv #:optional (hash-algo "sha256"))
|
(define* (bytevector->hash-data bv
|
||||||
|
#:optional
|
||||||
|
(hash-algo "sha256")
|
||||||
|
#:key (key-type 'ecc))
|
||||||
"Given BV, a bytevector containing a hash, return an s-expression suitable
|
"Given BV, a bytevector containing a hash, return an s-expression suitable
|
||||||
for use as the data for 'sign'."
|
for use as the data for 'sign'. KEY-TYPE must be a symbol: 'dsa, 'ecc, or
|
||||||
|
'rsa."
|
||||||
(string->canonical-sexp
|
(string->canonical-sexp
|
||||||
(format #f "(data (flags pkcs1) (hash \"~a\" #~a#))"
|
(format #f "(data (flags ~a) (hash \"~a\" #~a#))"
|
||||||
|
(case key-type
|
||||||
|
((ecc dsa) "rfc6979")
|
||||||
|
((rsa) "pkcs1")
|
||||||
|
(else (error "unknown key type" key-type)))
|
||||||
hash-algo
|
hash-algo
|
||||||
(bytevector->base16-string bv))))
|
(bytevector->base16-string bv))))
|
||||||
|
|
||||||
(define (hash-data->bytevector data)
|
(define (key-type sexp)
|
||||||
|
"Return a symbol denoting the type of key representing by SEXP--e.g., 'rsa',
|
||||||
|
'ecc'--or #f if SEXP does not denote a valid key."
|
||||||
|
(case (canonical-sexp-nth-data sexp 0)
|
||||||
|
((public-key private-key)
|
||||||
|
(canonical-sexp-nth-data (canonical-sexp-nth sexp 1) 0))
|
||||||
|
(else #f)))
|
||||||
|
|
||||||
|
(define* (hash-data->bytevector data)
|
||||||
"Return two values: the hash value (a bytevector), and the hash algorithm (a
|
"Return two values: the hash value (a bytevector), and the hash algorithm (a
|
||||||
string) extracted from DATA, an sexp as returned by 'bytevector->hash-data'.
|
string) extracted from DATA, an sexp as returned by 'bytevector->hash-data'.
|
||||||
Return #f if DATA does not conform."
|
Return #f if DATA does not conform."
|
||||||
|
|
|
@ -39,11 +39,12 @@
|
||||||
(call-with-input-file file
|
(call-with-input-file file
|
||||||
(compose string->canonical-sexp get-string-all)))
|
(compose string->canonical-sexp get-string-all)))
|
||||||
|
|
||||||
(define (read-hash-data file)
|
(define (read-hash-data file key-type)
|
||||||
"Read sha256 hash data from FILE and return it as a gcrypt sexp."
|
"Read sha256 hash data from FILE and return it as a gcrypt sexp. KEY-TYPE
|
||||||
|
is a symbol representing the type of public key algo being used."
|
||||||
(let* ((hex (call-with-input-file file get-string-all))
|
(let* ((hex (call-with-input-file file get-string-all))
|
||||||
(bv (base16-string->bytevector (string-trim-both hex))))
|
(bv (base16-string->bytevector (string-trim-both hex))))
|
||||||
(bytevector->hash-data bv)))
|
(bytevector->hash-data bv #:key-type key-type)))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
|
@ -64,7 +65,7 @@
|
||||||
(leave
|
(leave
|
||||||
(_ "cannot find public key for secret key '~a'~%")
|
(_ "cannot find public key for secret key '~a'~%")
|
||||||
key)))
|
key)))
|
||||||
(data (read-hash-data hash-file))
|
(data (read-hash-data hash-file (key-type public-key)))
|
||||||
(signature (signature-sexp data secret-key public-key)))
|
(signature (signature-sexp data secret-key public-key)))
|
||||||
(display (canonical-sexp->string signature))
|
(display (canonical-sexp->string signature))
|
||||||
#t))
|
#t))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
;; Test the (guix pk-crypto) module.
|
;; Test the (guix pk-crypto) module.
|
||||||
|
|
||||||
(define %key-pair
|
(define %key-pair
|
||||||
;; Key pair that was generated with:
|
;; RSA key pair that was generated with:
|
||||||
;; (generate-key (string->canonical-sexp "(genkey (rsa (nbits 4:1024)))"))
|
;; (generate-key (string->canonical-sexp "(genkey (rsa (nbits 4:1024)))"))
|
||||||
;; which takes a bit of time.
|
;; which takes a bit of time.
|
||||||
"(key-data
|
"(key-data
|
||||||
|
@ -48,6 +48,20 @@
|
||||||
(q #00E9AD22F158060BC9AE3601DA623AFC60FFF3058795802CA92371C00097335CF9A23D7782DE353C9DBA93D7BB99E6A24A411107605E722481C5C191F80D7EB77F#)
|
(q #00E9AD22F158060BC9AE3601DA623AFC60FFF3058795802CA92371C00097335CF9A23D7782DE353C9DBA93D7BB99E6A24A411107605E722481C5C191F80D7EB77F#)
|
||||||
(u #59B45B95AE01A7A7370FAFDB08FE73A4793CE37F228961B09B1B1E7DDAD9F8D3E28F5C5E8B4B067E6B8E0BBF3F690B42991A79E46108DDCDA2514323A66964DE#))))")
|
(u #59B45B95AE01A7A7370FAFDB08FE73A4793CE37F228961B09B1B1E7DDAD9F8D3E28F5C5E8B4B067E6B8E0BBF3F690B42991A79E46108DDCDA2514323A66964DE#))))")
|
||||||
|
|
||||||
|
(define %ecc-key-pair
|
||||||
|
;; Ed25519 key pair generated with:
|
||||||
|
;; (generate-key (string->canonical-sexp "(genkey (ecdsa (curve Ed25519) (flags rfc6979 transient)))"))
|
||||||
|
"(key-data
|
||||||
|
(public-key
|
||||||
|
(ecc
|
||||||
|
(curve Ed25519)
|
||||||
|
(q #94869C1B9E69DB8DD910B7F7F4D6E56A63A964A59AE8F90F6703ACDDF6F50C81#)))
|
||||||
|
(private-key
|
||||||
|
(ecc
|
||||||
|
(curve Ed25519)
|
||||||
|
(q #94869C1B9E69DB8DD910B7F7F4D6E56A63A964A59AE8F90F6703ACDDF6F50C81#)
|
||||||
|
(d #6EFB32D0B4EC6B3237B523539F1979379B82726AAA605EB2FBA6775B2B777B78#))))")
|
||||||
|
|
||||||
(test-begin "pk-crypto")
|
(test-begin "pk-crypto")
|
||||||
|
|
||||||
(let ((sexps '("(foo bar)"
|
(let ((sexps '("(foo bar)"
|
||||||
|
@ -148,8 +162,30 @@
|
||||||
(and (string=? algo "sha256")
|
(and (string=? algo "sha256")
|
||||||
(bytevector=? value bv))))))
|
(bytevector=? value bv))))))
|
||||||
|
|
||||||
|
(test-equal "key-type"
|
||||||
|
'(rsa ecc)
|
||||||
|
(map (compose key-type
|
||||||
|
(cut find-sexp-token <> 'public-key)
|
||||||
|
string->canonical-sexp)
|
||||||
|
(list %key-pair %ecc-key-pair)))
|
||||||
|
|
||||||
(test-assert "sign + verify"
|
(test-assert "sign + verify"
|
||||||
(let* ((pair (string->canonical-sexp %key-pair))
|
(let* ((pair (string->canonical-sexp %key-pair))
|
||||||
|
(secret (find-sexp-token pair 'private-key))
|
||||||
|
(public (find-sexp-token pair 'public-key))
|
||||||
|
(data (bytevector->hash-data
|
||||||
|
(sha256 (string->utf8 "Hello, world."))
|
||||||
|
#:key-type (key-type public)))
|
||||||
|
(sig (sign data secret)))
|
||||||
|
(and (verify sig data public)
|
||||||
|
(not (verify sig
|
||||||
|
(bytevector->hash-data
|
||||||
|
(sha256 (string->utf8 "Hi!"))
|
||||||
|
#:key-type (key-type public))
|
||||||
|
public)))))
|
||||||
|
|
||||||
|
(test-assert "sign + verify, Ed25519"
|
||||||
|
(let* ((pair (string->canonical-sexp %ecc-key-pair))
|
||||||
(secret (find-sexp-token pair 'private-key))
|
(secret (find-sexp-token pair 'private-key))
|
||||||
(public (find-sexp-token pair 'public-key))
|
(public (find-sexp-token pair 'public-key))
|
||||||
(data (bytevector->hash-data
|
(data (bytevector->hash-data
|
||||||
|
|
Loading…
Reference in New Issue