mac.scm 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. ;;; guile-gcrypt --- crypto tooling for guile
  2. ;;; Copyright © 2016 Christine Lemmer-Webber <cwebber@dustycloud.org>
  3. ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com>
  4. ;;; Copyright © 2019, 2020, 2022 Ludovic Courtès <ludo@gnu.org>
  5. ;;;
  6. ;;; This file is part of guile-gcrypt.
  7. ;;;
  8. ;;; guile-gcrypt is free software; you can redistribute it and/or
  9. ;;; modify it under the terms of the GNU Lesser General Public License
  10. ;;; as published by the Free Software Foundation; either version 3 of
  11. ;;; the License, or (at your option) any later version.
  12. ;;;
  13. ;;; guile-gcrypt is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. ;;; Lesser General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU Lesser General Public License
  19. ;;; along with guile-gcrypt. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (gcrypt mac)
  21. #:use-module (ice-9 format)
  22. #:use-module (ice-9 match)
  23. #:use-module (gcrypt base64)
  24. #:use-module (gcrypt internal)
  25. #:use-module (gcrypt random)
  26. #:use-module (rnrs bytevectors)
  27. #:use-module (system foreign)
  28. #:export (mac-algorithm
  29. lookup-mac-algorithm
  30. mac-algorithm-name
  31. mac-size
  32. sign-data
  33. sign-data-base64
  34. valid-signature?
  35. valid-base64-signature?
  36. generate-signing-key))
  37. (define-syntax-rule (define-syntax-public name value)
  38. (begin
  39. (define-syntax name value)
  40. (export name)))
  41. (define-syntax-rule (define-mac-algorithms name->integer
  42. symbol->integer integer->symbol mac-size
  43. (name id size) ...)
  44. "Define hash algorithms with their NAME, numerical ID, and SIZE in bytes."
  45. (begin
  46. ;; Make sure NAME is bound to follow best practices for syntax matching
  47. ;; (info "(guile) Syntax Rules").
  48. (define-syntax-public name
  49. (lambda (s)
  50. (syntax-violation 'name "\
  51. syntactic keyword is meant to be used with 'mac-algorithm'"
  52. s s)))
  53. ...
  54. (define-enumerate-type name->integer symbol->integer integer->symbol
  55. (name id) ...)
  56. (define-lookup-procedure mac-size
  57. "Return the size in bytes of a digest of the given hash algorithm."
  58. (id size) ...)))
  59. (define-mac-algorithms mac-algorithm
  60. lookup-mac-algorithm mac-algorithm-name
  61. mac-size
  62. ;; GCRY_MAC_*
  63. (hmac-sha256 101 32)
  64. (hmac-sha224 102 28)
  65. (hmac-sha512 103 64)
  66. (hmac-sha384 104 48)
  67. (hmac-sha1 105 20)
  68. (hmac-md5 106 16)
  69. (hmac-md4 107 16)
  70. (hmac-rmd160 108 20)
  71. (hmac-tiger1 109 24)
  72. (hmac-whirlpool 110 64)
  73. (hmac-gostr3411-94 111 32)
  74. (hmac-stribog256 112 32)
  75. (hmac-stribog512 113 64)
  76. ;; (hmac-md2 114 0)
  77. (hmac-sha3-224 115 28)
  78. (hmac-sha3-256 116 32)
  79. (hmac-sha3-384 117 48)
  80. (hmac-sha3-512 118 64)
  81. (hmac-gostr3411-cp 119 32)
  82. (hmac-blake2b-512 120 64)
  83. (hmac-blake2b-384 121 48)
  84. (hmac-blake2b-256 122 32)
  85. (hmac-blake2b-160 123 20)
  86. (hmac-blake2s-256 124 32)
  87. (hmac-blake2s-224 125 28)
  88. (hmac-blake2s-160 126 20)
  89. (hmac-blake2s-128 127 16)
  90. (hmac-sm3 128 32)
  91. (hmac-sha512-256 129 32)
  92. (hmac-sha512-224 130 28)
  93. (cmac-aes 201 16)
  94. (cmac-3des 202 8)
  95. (cmac-camellia 203 16)
  96. (cmac-cast5 204 8)
  97. (cmac-blowfish 205 8)
  98. (cmac-twofish 206 16)
  99. (cmac-serpent 207 16)
  100. (cmac-seed 208 16)
  101. (cmac-rfc2268 209 8)
  102. (cmac-idea 210 8)
  103. (cmac-gost28147 211 8)
  104. (gmac-aes 401 16)
  105. (gmac-camellia 402 16)
  106. (gmac-twofish 403 16)
  107. (gmac-serpent 404 16)
  108. (gmac-seed 405 16)
  109. (poly1305 501 16)
  110. (poly1305-aes 502 16)
  111. (poly1305-camellia 503 16)
  112. (poly1305-twofish 504 16)
  113. (poly1305-serpent 505 16)
  114. (poly1305-seed 506 16))
  115. (define mac-algo-maclen
  116. ;; This procedure was used to double-check the hash sizes above. (We
  117. ;; cannot use it at macro-expansion time because it wouldn't work when
  118. ;; cross-compiling.)
  119. (libgcrypt->procedure int "gcry_mac_get_algo_maclen" `(,int)))
  120. (define %no-error 0) ; GPG_ERR_NO_ERROR
  121. (define-wrapped-pointer-type <mac>
  122. mac?
  123. pointer->mac mac->pointer
  124. (lambda (mac port)
  125. (format port "#<mac ~x>"
  126. (pointer-address (mac->pointer mac)))))
  127. (define %gcry-mac-open
  128. (libgcrypt->procedure int "gcry_mac_open"
  129. ;; gcry_mac_hd_t *HD, int ALGO,
  130. ;; unsigned int FLAGS, gcry_ctx_t CTX
  131. `(* ,int ,unsigned-int *)))
  132. (define (mac-open algorithm)
  133. "Create a <mac> object set to use ALGORITHM"
  134. (let* ((mac (bytevector->pointer (make-bytevector (sizeof '*))))
  135. (err (%gcry-mac-open mac algorithm 0 %null-pointer)))
  136. (if (= err 0)
  137. (pointer->mac (dereference-pointer mac))
  138. (throw 'gcry-error 'mac-open err))))
  139. (define %gcry-mac-setkey
  140. (libgcrypt->procedure int "gcry_mac_setkey" `(* * ,size_t)))
  141. (define (mac-setkey mac key)
  142. "Set the KEY on <mac> object MAC
  143. In our case, KEY is either a string or a bytevector."
  144. (let* ((key (match key
  145. ((? bytevector? key)
  146. key)
  147. ((? string? key)
  148. (string->utf8 key))))
  149. (err (%gcry-mac-setkey (mac->pointer mac)
  150. (bytevector->pointer key)
  151. (bytevector-length key))))
  152. (if (= err 0)
  153. #t
  154. (throw 'gcry-error 'mac-setkey err))))
  155. (define mac-close
  156. (let ((proc (libgcrypt->procedure void
  157. "gcry_mac_close"
  158. '(*)))) ; gcry_mac_hd_t H
  159. (lambda (mac)
  160. "Release all resources of MAC.
  161. Running this on an already closed <mac> might segfault :)"
  162. (proc (mac->pointer mac)))))
  163. (define mac-write
  164. (let ((proc (libgcrypt->procedure int
  165. "gcry_mac_write"
  166. `(* * ,size_t))))
  167. (lambda (mac obj)
  168. "Writes string or bytevector OBJ to MAC"
  169. (let* ((bv (match obj
  170. ((? bytevector? obj)
  171. obj)
  172. ((? string? obj)
  173. (string->utf8 obj))))
  174. (err (proc (mac->pointer mac)
  175. (bytevector->pointer bv)
  176. (bytevector-length bv))))
  177. (if (= err 0)
  178. #t
  179. (throw 'gcry-error 'mac-write err))))))
  180. (define mac-read
  181. (let ((proc (libgcrypt->procedure int
  182. "gcry_mac_read"
  183. `(* * *))))
  184. (lambda (mac algorithm)
  185. "Get bytevector representing result of MAC's written, signed data"
  186. (define (int-bv* n)
  187. ;; Get the pointer to a bytevector holding an integer with this number
  188. (let ((bv (make-bytevector (sizeof int))))
  189. (bytevector-uint-set! bv 0 n (native-endianness) (sizeof int))
  190. (bytevector->pointer bv)))
  191. (let* ((bv-len (mac-size algorithm))
  192. (bv (make-bytevector bv-len))
  193. (err (proc (mac->pointer mac)
  194. (bytevector->pointer bv)
  195. (int-bv* bv-len))))
  196. (if (= err 0)
  197. bv
  198. (throw 'gcry-error 'mac-read err))))))
  199. ;; GPG_ERR_CHECKSUM *should* be 10, but it seems to return here as
  200. ;; 16777226... unfortunately this is because we're pulling back an integer
  201. ;; rather than the gcry_error_t type.
  202. (define mac-verify
  203. (let ((proc (libgcrypt->procedure int
  204. "gcry_mac_verify"
  205. `(* * ,size_t))))
  206. (lambda (mac bv)
  207. "Verify that BV matches result calculated in MAC
  208. BV should be a bytevector with previously calculated data."
  209. (let ((err (proc (mac->pointer mac)
  210. (bytevector->pointer bv)
  211. (bytevector-length bv))))
  212. (if (= err 0)
  213. (values #t err)
  214. ;; TODO: This is WRONG! See the comment above
  215. ;; this procedure's definition for why. If we could
  216. ;; parse it as the appropriate GPG error, GPG_ERR_CHECKSUM
  217. ;; should be 10.
  218. (values #f err))))))
  219. (define* (sign-data key data #:key
  220. (algorithm (mac-algorithm hmac-sha512)))
  221. "Signs DATA with KEY for ALGORITHM. Returns a bytevector."
  222. (let ((mac (mac-open algorithm)))
  223. (mac-setkey mac key)
  224. (mac-write mac data)
  225. (let ((result (mac-read mac algorithm)))
  226. (mac-close mac)
  227. result)))
  228. (define* (sign-data-base64 key data #:key
  229. (algorithm (mac-algorithm hmac-sha512)))
  230. "Like sign-data, but conveniently encodes to base64."
  231. (base64-encode (sign-data key data #:algorithm algorithm)))
  232. (define* (valid-signature? key data sig
  233. #:key (algorithm (mac-algorithm hmac-sha512)))
  234. "Verify that DATA with KEY matches previous signature SIG for ALGORITHM."
  235. (let ((mac (mac-open algorithm)))
  236. (mac-setkey mac key)
  237. (mac-write mac data)
  238. (let ((result (mac-verify mac sig)))
  239. (mac-close mac)
  240. result)))
  241. (define* (valid-base64-signature? key data b64-sig
  242. #:key
  243. (algorithm (mac-algorithm hmac-sha512)))
  244. (valid-signature? key data
  245. (base64-decode b64-sig)
  246. #:algorithm algorithm))
  247. (define* (generate-signing-key #:optional (key-length 128))
  248. "Generate a signing key (a bytevector).
  249. KEY-LENGTH is the length, in bytes, of the key. The default is 128.
  250. This should be a multiple of 8."
  251. (gen-random-bv key-length %gcry-very-strong-random))