# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: address@hidden # target_branch: bzr+ssh://address@hidden/emacs/trunk/ # testament_sha1: ef8ed3601dbb5399866cdbd6ac3403ff307c237e # timestamp: 2013-10-06 04:58:53 -0400 # base_revision_id: address@hidden # # Begin patch === modified file 'configure.ac' --- configure.ac 2013-09-25 03:44:34 +0000 +++ configure.ac 2013-10-06 08:57:33 +0000 @@ -236,6 +236,7 @@ OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) +OPTION_DEFAULT_ON([nettle],[don't use -lhogweed (libnettle) for cryptographic support]) OPTION_DEFAULT_ON([zlib],[don't compile with zlib decompression support]) AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB], @@ -2443,6 +2444,25 @@ AC_SUBST(LIBGNUTLS_LIBS) AC_SUBST(LIBGNUTLS_CFLAGS) +HAVE_NETTLE=no +if test "${with_nettle}" = "yes" ; then + PKG_CHECK_MODULES([LIBNETTLE], [hogweed >= 2.7], HAVE_NETTLE=yes, HAVE_NETTLE=no) + if test "${HAVE_NETTLE}" = "yes"; then + AC_DEFINE(HAVE_NETTLE, 1, [Define if using libnettle+libhogweed.]) + fi + + # Windows loads libnettle dynamically + if test "${opsys}" = "mingw32"; then + LIBNETTLE_LIBS= + else + CFLAGS="$CFLAGS $LIBNETTLE_CFLAGS" + LIBS="$LIBNETTLE_LIBS $LIBS" + fi +fi + +AC_SUBST(LIBNETTLE_LIBS) +AC_SUBST(LIBNETTLE_CFLAGS) + NOTIFY_OBJ= NOTIFY_SUMMARY=no @@ -4934,6 +4954,7 @@ echo " Does Emacs use access control lists? ${acl_summary}" echo " Does Emacs use -lselinux? ${HAVE_LIBSELINUX}" echo " Does Emacs use -lgnutls? ${HAVE_GNUTLS}" +echo " Does Emacs use -lhogweed (libnettle)? ${HAVE_NETTLE}" echo " Does Emacs use -lxml2? ${HAVE_LIBXML2}" echo " Does Emacs use -lfreetype? ${HAVE_FREETYPE}" === added file 'lisp/nettle.el' --- lisp/nettle.el 1970-01-01 00:00:00 +0000 +++ lisp/nettle.el 2013-10-06 08:57:33 +0000 @@ -0,0 +1,335 @@ +;;; nettle.el --- Interface to libnettle/libhogweed -*- lexical-binding: t; -*- + +;; Copyright (C) 2013 Teodor Zlatanov + +;; Author: Teodor Zlatanov +;; Keywords: data + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Provides basic functions to interface with libnettle and libhogweed +;; through nettle.c + +;; Test with ./emacs --batch --load "/path/to/nettle.el" -f ert-run-tests-batch + +;;; Code: + +(require 'cl) +(require 'ert) +(require 'hex-util) + +;;;###autoload +(defcustom nettle-payloads-store-secrets nil + "Whether the Nettle interface should store secrets in the payloads. +The secrets are: the key, the IV, and the original input. +Set this to t if you're debugging." + :version "24.4" + :type 'boolean) + +(cl-defstruct nettle-payload length data key iv input cipher cipher-mode) + +(defun nettle-payload-hexdump (payload) + (encode-hex-string (nettle-payload-data payload))) + +(defun nettle-payload-fulldump (payload) + (let ((key (funcall (nettle-payload-key payload))) + (iv (funcall (nettle-payload-iv payload))) + (input (funcall (nettle-payload-input payload)))) + (format "%s with cipher %s, key(%d) %S, IV(%d) %S, input(%d) %S => (%d) %s" + (nettle-payload-cipher-mode payload) + (nettle-payload-cipher payload) + (length key) (when key (encode-hex-string key)) + (length iv) (when iv (encode-hex-string iv)) + (length input) (when input (encode-hex-string input)) + (nettle-payload-length payload) + (nettle-payload-hexdump payload)))) + +(defsubst nettle-make-secret (secret) + (if nettle-payloads-store-secrets + (lexical-let ((p (copy-sequence secret))) + (lambda () p)) + (lambda () nil))) + +(defun nettle-encrypt (input key iv cipher cipher-mode) + (make-nettle-payload :length (length input) + :cipher cipher + :cipher-mode cipher-mode + :input (nettle-make-secret input) + :key (nettle-make-secret key) + :iv (nettle-make-secret iv) + :data (nettle-crypt t input key iv cipher cipher-mode))) + +(defun nettle-decrypt (payload key iv cipher cipher-mode) + (let ((data (nettle-crypt + nil + (nettle-payload-data payload) + key iv cipher cipher-mode))) + (substring data 0 (nettle-payload-length payload)))) + +(ert-deftest test-nettle-001-hashes () + "Test the Nettle hashing functions" + (progn + ;; we expect at least 7 hash methods + (should (> (length (nettle-hashes)) 7)) + (let* ((inputs '("" + "some data" + "lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data " + "data and more data to go over the block limit!" + "data and more data to go over the block limit")) + (algomap '(md5 sha1 sha224 sha256 sha384 sha512)) + ;; only test the algorithms supported by `secure-hash' + (hashes (delete nil (mapcar + (lambda (x) + (let ((sym (intern (car x)))) + (car (member sym algomap)))) + (nettle-hashes))))) + (dolist (hash hashes) + (dolist (input inputs) + ;; we use encode-hex-string to ensure the tests are readable + (should (string-equal (encode-hex-string (nettle-hash + input + (symbol-name hash))) + (encode-hex-string (secure-hash + hash + input + nil nil t))))))))) + +(ert-deftest test-nettle-002-ciphers () + "Test the Nettle ciphers" + ;; we expect at least 10 ciphers + (should (> (length (nettle-ciphers)) 10)) + (let ((keys '("mykey" "mykey2")) + (inputs '("" + "some data" + "lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data lots and lots of data " + "data and more data to go over the block limit!" + "data and more data to go over the block limit")) + (ivs '("" "init" "init2")) + ; arcfour128 generates a FPE, disabled for now + (ciphers (delete "arcfour128" (mapcar 'car (nettle-ciphers)))) + (cipher-modes (nettle-cipher-modes)) + tests test test2 result dump payload) + + (dolist (mode cipher-modes) + (dolist (cipher ciphers) + (dolist (iv ivs) + (dolist (input inputs) + (dolist (key keys) + (setq tests (cons (list input key iv cipher mode) + tests))))))) + + (while (setq test (pop tests)) + ;; test2 = the original test but replacing the input with the payload + (setq test2 (copy-sequence test)) + (setq payload (apply 'nettle-encrypt test)) + (setf (nth 0 test2) payload) + + (setq result (apply 'nettle-decrypt test2)) + + (should (string-equal (car test) result))))) + +;;; Testing from the command line: +;;; echo e36a9d13c15a6df23a59a6337d6132b8f7cd5283cb4784b81141b52343a18e5f5e5ee8f5553c23167409dd222478bc30 | perl -lne 'print pack "H*", $_' | openssl enc -aes-128-ctr -d -nosalt -K 6d796b657932 -iv 696e697432 | od -x +;;; Testing the equivalent CTR encryption: +;;; (message "\t 111 \t %s" (nettle-payload-fulldump (nettle-encrypt "data and more data to go over the block limit" "mykey2" "init2" "aes128" "CTR"))) +;;; (message "\t 222 \t %s" (nettle-payload-fulldump (nettle-encrypt (decode-hex-string "e36a9d13c15a6df23a59a6337d6132b8f7cd5283cb4784b81141b52343a18e5f5e5ee8f5553c23167409dd222478bc30") "mykey2" "init2" "aes128" "CTR"))) +;;; (message "\t 333 \t %s" (encode-hex-string (nettle-crypt t (decode-hex-string "e36a9d13c15a6df23a59a6337d6132b8f7cd5283cb4784b81141b52343a18e5f5e5ee8f5553c23167409dd222478bc30") "mykey2" "init2" "aes128" "CTR"))) +;;; (message "\t 444 \t %s" (encode-hex-string (nettle-crypt nil (decode-hex-string "e36a9d13c15a6df23a59a6337d6132b8f7cd5283cb4784b81141b52343a18e5f5e5ee8f5553c23167409dd222478bc30") "mykey2" "init2" "aes128" "CTR"))) + +(ert-deftest test-nettle-003-more-ciphers () + "Test the Nettle ciphers from a test set" + (let ((tests '( + ("5d563f6d1cccf236051c0c5c1c58f28f" "f69f2445df4f9b17ad2b417be66c3710" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "e31a6055297d96ca3330cdf1b1860a83" "camellia256" "CBC") + ("e31a6055297d96ca3330cdf1b1860a83" "30c81c46a35ce411e5fbc1191a0a52ef" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "36cbeb73bd504b4070b1b7de2b21eb50" "camellia256" "CBC") + ("36cbeb73bd504b4070b1b7de2b21eb50" "ae2d8a571e03ac9c9eb76fac45af8e51" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "e6cfa35fc02b134a4d2c0b6737ac3eda" "camellia256" "CBC") + ("e6cfa35fc02b134a4d2c0b6737ac3eda" "6bc1bee22e409f96e93d7e117393172a" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "000102030405060708090a0b0c0d0e0f" "camellia256" "CBC") + ("01faaa930b4ab9916e9668e1428c6b08" "f69f2445df4f9b17ad2b417be66c3710" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "37d359c3349836d884e310addf68c449" "camellia192" "CBC") + ("37d359c3349836d884e310addf68c449" "30c81c46a35ce411e5fbc1191a0a52ef" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "5d5a869bd14ce54264f892a6dd2ec3d5" "camellia192" "CBC") + ("5d5a869bd14ce54264f892a6dd2ec3d5" "ae2d8a571e03ac9c9eb76fac45af8e51" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "2a4830ab5ac4a1a2405955fd2195cf93" "camellia192" "CBC") + ("2a4830ab5ac4a1a2405955fd2195cf93" "6bc1bee22e409f96e93d7e117393172a" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "000102030405060708090a0b0c0d0e0f" "camellia192" "CBC") + ("74c64268cdb8b8faf5b34e8af3732980" "f69f2445df4f9b17ad2b417be66c3710" "2b7e151628aed2a6abf7158809cf4f3c" "36a84cdafd5f9a85ada0f0a993d6d577" "camellia128" "CBC") + ("0f06165008cf8b8b5a63586362543e54" "30c81c46a35ce411e5fbc1191a0a52ef" "2b7e151628aed2a6abf7158809cf4f3c" "a2f2cf671629ef7840c5a5dfb5074887" "camellia128" "CBC") + ("a2f2cf671629ef7840c5a5dfb5074887" "ae2d8a571e03ac9c9eb76fac45af8e51" "2b7e151628aed2a6abf7158809cf4f3c" "1607cf494b36bbf00daeb0b503c831ab" "camellia128" "CBC") + ("1607cf494b36bbf00daeb0b503c831ab" "6bc1bee22e409f96e93d7e117393172a" "2b7e151628aed2a6abf7158809cf4f3c" "000102030405060708090a0b0c0d0e0f" "camellia128" "CBC") + ("7960109fb6dc42947fcfe59ea3c5eb6b" "f69f2445df4f9b17ad2b417be66c3710" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "camellia256" "ECB") + ("a623d711dc5f25a51bb8a80d56397d28" "30c81c46a35ce411e5fbc1191a0a52ef" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "camellia256" "ECB") + ("c91d3a8f1aea08a9386cf4b66c0169ea" "ae2d8a571e03ac9c9eb76fac45af8e51" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "camellia256" "ECB") + ("befd219b112fa00098919cd101c9ccfa" "6bc1bee22e409f96e93d7e117393172a" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "camellia256" "ECB") + ("909dbd95799096748cb27357e73e1d26" "f69f2445df4f9b17ad2b417be66c3710" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "camellia192" "ECB") + ("b40ed2b60eb54d09d030cf511feef366" "30c81c46a35ce411e5fbc1191a0a52ef" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "camellia192" "ECB") + ("5713c62c14b2ec0f8393b6afd6f5785a" "ae2d8a571e03ac9c9eb76fac45af8e51" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "camellia192" "ECB") + ("cccc6c4e138b45848514d48d0d3439d3" "6bc1bee22e409f96e93d7e117393172a" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "camellia192" "ECB") + ("e61925e0d5dfaa9bb29f815b3076e51a" "f69f2445df4f9b17ad2b417be66c3710" "2b7e151628aed2a6abf7158809cf4f3c" "" "camellia128" "ECB") + ("a0a1abcd1893ab6fe0fe5b65df5f8636" "30c81c46a35ce411e5fbc1191a0a52ef" "2b7e151628aed2a6abf7158809cf4f3c" "" "camellia128" "ECB") + ("0be1f14023782a22e8384c5abb7fab2b" "ae2d8a571e03ac9c9eb76fac45af8e51" "2b7e151628aed2a6abf7158809cf4f3c" "" "camellia128" "ECB") + ("432fc5dcd628115b7c388d770b270c96" "6bc1bee22e409f96e93d7e117393172a" "2b7e151628aed2a6abf7158809cf4f3c" "" "camellia128" "ECB") + ("2edf1f3418d53b88841fc8985fb1ecf2" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" "" "camellia256" "ECB") + ("b22f3c36b72d31329eee8addc2906c68" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f1011121314151617" "" "camellia192" "ECB") + ("77cf412067af8270613529149919546f" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f" "" "camellia128" "ECB") + ("9acc237dff16d76c20ef7c919e3a7509" "0123456789abcdeffedcba9876543210" "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff" "" "camellia256" "ECB") + ("b4993401b3e996f84ee5cee7d79b09b9" "0123456789abcdeffedcba9876543210" "0123456789abcdeffedcba98765432100011223344556677" "" "camellia192" "ECB") + ("67673138549669730857065648eabe43" "0123456789abcdeffedcba9876543210" "0123456789abcdeffedcba9876543210" "" "camellia128" "ECB") + ("eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223" "ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d" "001cc5b751a51d70a1c1114800000001" "aes256" "CTR") + ("f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" "f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884" "00faac24c1585ef15a43d87500000001" "aes256" "CTR") + ("145ad01dbf824ec7560863dc71e3e0c0" "53696e676c6520626c6f636b206d7367" "776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104" "00000060db5672c97aa8f0b200000001" "aes256" "CTR") + ("96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223" "02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe" "0007bdfd5cbd60278dcc091200000001" "aes192" "CTR") + ("453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" "7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a" "0096b03b020c6eadc2cb500d00000001" "aes192" "CTR") + ("4b55384fe259c9c84e7935a003cbe928" "53696e676c6520626c6f636b206d7367" "16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515" "0000004836733c147d6d93cb00000001" "aes192" "CTR") + ("c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223" "7691be035e5020a8ac6e618529f9a0dc" "00e0017b27777f3f4a1786f000000001" "aes128" "CTR") + ("5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" "7e24067817fae0d743d6ce1f32539163" "006cb6dbc0543b59da48d90b00000001" "aes128" "CTR") + ("e4095d4fb7a7b3792d6175a3261311b8" "53696e676c6520626c6f636b206d7367" "ae6852f8121067cc4bf7a5765577f39e" "00000030000000000000000000000001" "aes128" "CTR") + ("b2eb05e2c39be9fcda6c19078c6a9d1b" "f69f2445df4f9b17ad2b417be66c3710" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "39f23369a9d9bacfa530e26304231461" "aes256" "CBC") + ("39f23369a9d9bacfa530e26304231461" "30c81c46a35ce411e5fbc1191a0a52ef" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "9cfc4e967edb808d679f777bc6702c7d" "aes256" "CBC") + ("9cfc4e967edb808d679f777bc6702c7d" "ae2d8a571e03ac9c9eb76fac45af8e51" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "f58c4c04d6e5f1ba779eabfb5f7bfbd6" "aes256" "CBC") + ("f58c4c04d6e5f1ba779eabfb5f7bfbd6" "6bc1bee22e409f96e93d7e117393172a" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "000102030405060708090a0b0c0d0e0f" "aes256" "CBC") + ("08b0e27988598881d920a9e64f5615cd" "f69f2445df4f9b17ad2b417be66c3710" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "571b242012fb7ae07fa9baac3df102e0" "aes192" "CBC") + ("571b242012fb7ae07fa9baac3df102e0" "30c81c46a35ce411e5fbc1191a0a52ef" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "b4d9ada9ad7dedf4e5e738763f69145a" "aes192" "CBC") + ("b4d9ada9ad7dedf4e5e738763f69145a" "ae2d8a571e03ac9c9eb76fac45af8e51" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "4f021db243bc633d7178183a9fa071e8" "aes192" "CBC") + ("4f021db243bc633d7178183a9fa071e8" "6bc1bee22e409f96e93d7e117393172a" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "000102030405060708090a0b0c0d0e0f" "aes192" "CBC") + ("3ff1caa1681fac09120eca307586e1a7" "f69f2445df4f9b17ad2b417be66c3710" "2b7e151628aed2a6abf7158809cf4f3c" "73bed6b8e3c1743b7116e69e22229516" "aes128" "CBC") + ("73bed6b8e3c1743b7116e69e22229516" "30c81c46a35ce411e5fbc1191a0a52ef" "2b7e151628aed2a6abf7158809cf4f3c" "5086cb9b507219ee95db113a917678b2" "aes128" "CBC") + ("5086cb9b507219ee95db113a917678b2" "ae2d8a571e03ac9c9eb76fac45af8e51" "2b7e151628aed2a6abf7158809cf4f3c" "7649abac8119b246cee98e9b12e9197d" "aes128" "CBC") + ("7649abac8119b246cee98e9b12e9197d" "6bc1bee22e409f96e93d7e117393172a" "2b7e151628aed2a6abf7158809cf4f3c" "000102030405060708090a0b0c0d0e0f" "aes128" "CBC") + ("23304b7a39f9f3ff067d8d8f9e24ecc7" "f69f2445df4f9b17ad2b417be66c3710" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "aes256" "ECB") + ("b6ed21b99ca6f4f9f153e7b1beafed1d" "30c81c46a35ce411e5fbc1191a0a52ef" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "aes256" "ECB") + ("591ccb10d410ed26dc5ba74a31362870" "ae2d8a571e03ac9c9eb76fac45af8e51" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "aes256" "ECB") + ("f3eed1bdb5d2a03c064b5a7e3db181f8" "6bc1bee22e409f96e93d7e117393172a" "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" "" "aes256" "ECB") + ("9a4b41ba738d6c72fb16691603c18e0e" "f69f2445df4f9b17ad2b417be66c3710" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "aes192" "ECB") + ("ef7afd2270e2e60adce0ba2face6444e" "30c81c46a35ce411e5fbc1191a0a52ef" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "aes192" "ECB") + ("974104846d0ad3ad7734ecb3ecee4eef" "ae2d8a571e03ac9c9eb76fac45af8e51" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "aes192" "ECB") + ("bd334f1d6e45f25ff712a214571fa5cc" "6bc1bee22e409f96e93d7e117393172a" "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" "" "aes192" "ECB") + ("7b0c785e27e8ad3f8223207104725dd4" "f69f2445df4f9b17ad2b417be66c3710" "2b7e151628aed2a6abf7158809cf4f3c" "" "aes128" "ECB") + ("43b1cd7f598ece23881b00e3ed030688" "30c81c46a35ce411e5fbc1191a0a52ef" "2b7e151628aed2a6abf7158809cf4f3c" "" "aes128" "ECB") + ("f5d3d58503b9699de785895a96fdbaaf" "ae2d8a571e03ac9c9eb76fac45af8e51" "2b7e151628aed2a6abf7158809cf4f3c" "" "aes128" "ECB") + ("3ad77bb40d7a3660a89ecaf32466ef97" "6bc1bee22e409f96e93d7e117393172a" "2b7e151628aed2a6abf7158809cf4f3c" "" "aes128" "ECB") + ("8ea2b7ca516745bfeafc49904b496089" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" "" "aes256" "ECB") + ("dda97ca4864cdfe06eaf70a0ec0d7191" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f1011121314151617" "" "aes192" "ECB") + ("69c4e0d86a7b0430d8cdb78070b4c55a" "00112233445566778899aabbccddeeff" "000102030405060708090a0b0c0d0e0f" "" "aes128" "ECB") + )) + test expected payload result) + (while (setq test (pop tests)) + ;; (message "Testing 003-ciphers %S" test) + (setf (nth 1 test) (decode-hex-string (nth 1 test))) + (setf (nth 2 test) (decode-hex-string (nth 2 test))) + (setf (nth 3 test) (decode-hex-string (nth 3 test))) + (setq expected (pop test)) + (setq payload (apply 'nettle-encrypt test)) + (setq result (substring (nettle-payload-data payload) + 0 + (nettle-payload-length payload))) + (should (string-equal (encode-hex-string result) + expected))))) + +(ert-deftest test-nettle-004-more-hashes () + "Test the Nettle hashes from a test set" + (let ((tests '(("57edf4a22be3c955ac49da2e2107b67a" "12345678901234567890123456789012345678901234567890123456789012345678901234567890" "md5") + ("d174ab98d277d9f5a5611c2c9f419d9f" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" "md5") + ("c3fcd3d76192e4007dfb496cca67e13b" "abcdefghijklmnopqrstuvwxyz" "md5") + ("f96b697d7cb7938d525a2f31aaf161d0" "message digest" "md5") + ("900150983cd24fb0d6963f7d28e17f72" "abc" "md5") + ("0cc175b9c0f1b6a831c399e269772661" "a" "md5") + ("a9993e364706816aba3e25717850c26c9cd0d89d" "abc" "sha1"))) + test expected) + (while (setq test (pop tests)) + ;; (message "Testing 004-hashes %S" test) + (setq expected (pop test)) + (should (string-equal (encode-hex-string (apply 'nettle-hash test)) + expected))))) + +(ert-deftest test-nettle-005-hmac-hashes () + "Test the Nettle HMAC hashes from a test set" + (let ((tests '(("f5c5021e60d9686fef3bb0414275fe4163bece61d9a95fec7a273746a437b986" "hello\n" "test" "sha256") + ("46b75292b81002fd873e89c532a1b8545d6efc9822ee938feba6de2723161a67" "more and more data goes into a file to exceed the buffer size" "test" "sha256") + ("81568ba71fa2c5f33cc84bf362466988f98eba3735479100b4e8908acad87ac4" "more and more data goes into a file to exceed the buffer size" "very long key goes here to exceed the key size" "sha256") + ("4bc830005783a73b8112f4bd5f4aa5f92e05b51e9b55c0cd6f9a7bee48371def" "more and more data goes into a file to exceed the buffer size" "" "sha256"))) + test expected) + (while (setq test (pop tests)) + ;; (message "Testing 005-hmacs %S" test) + (setq expected (pop test)) + (should (string-equal (encode-hex-string (apply 'nettle-hmac test)) + expected))))) + +(ert-deftest test-nettle-006-pbkdf2-RFC-6070 () + "Test the Nettle PBKDF2 SHA1 hashing with the RFC 6070 test set" + (should (string-equal (encode-hex-string (nettle-pbkdf2 "pass\000word" "sa\000lt" 4096 16 "sha1")) + "56fa6aa75548099dcc37d7f03425e0c3")) + (let ((tests '("0c60c80f961f0e71f3a9b524af6012062fe037a6:password:salt:1:x:sha1" + "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957:password:salt:2:x:sha1" + "4b007901b765489abead49d926f721d065a429c1:password:salt:4096:x:sha1" + ;; "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984:password:salt:16777216:x:sha1" ;; enable for a speed test :) + "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038:passwordPASSWORDpassword:saltSALTsaltSALTsaltSALTsaltSALTsalt:4096:x:sha1")) + test expected) + (while (and tests (setq test (split-string (pop tests) ":"))) + (setq expected (pop test)) + (setf (nth 2 test) (string-to-number (nth 2 test))) + (setf (nth 3 test) (length (decode-hex-string expected))) + ;; (message "Testing 006-pbkdf2-RFC-6070 %S" test) + (should (string-equal (encode-hex-string (apply 'nettle-pbkdf2 test)) + expected))))) + +(ert-deftest test-nettle-007-rsa-verify () + "Test the Nettle RSA signature verification" + ;; signature too short + (should-error (nettle-rsa-verify "Test the Nettle RSA signature" + "" + "Test the Nettle RSA signature" + "sha1")) + + ;; key too short + (should-error (nettle-rsa-verify "Test the Nettle RSA signature" + "Test the Nettle RSA signature" + "" + "sha1")) + + ;; invalid hashing method + (should-error (nettle-rsa-verify "Test the Nettle RSA signature" + "Test the Nettle RSA signature" + "" + "no such method")) + + ;; key generated with: + ;; openssl genrsa -out privkey.pem 2048 + ;; openssl rsa -in privkey.pem -pubout > pubkey.pem + (let* ((key (substring " +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreGA/Qky9W3izQV0kzba +7wKl/wzwxkbbQxvcUqUT1krgAbO/n1tYFjXdJZoWwbMO/qv7NRoMDY4yPWGpsQfY ++PSIknAhTZVbgwXrm/wb37+hKRKax2UZ9A/Rx4vJZRYlkpvZ9LbBziseFNN7SMWW +qkjBO/NeT8/I9mURDa+4RoYfT6ZwjTvt808PH7uIghk+MHAx9EMBAfafF1Jn9TqW +y+Hgdqik9sZteMvCumvGK4grSwzdfPO5I05tt/0I7QVPxlXbHIk/bBsE7mpgOxur +P0DAkFKtYDM7oZPBwB6X778ba2EEFKPpVIyzw/jlDPd9PB6gE6dixmax3Hlg69RI +EwIDAQAB +-----END PUBLIC KEY----- +" 28 426)) + ;; 24 skipped bytes are the header + (key-bitstring (substring (base64-decode-string key) 24))) + ;; invalid signature, valid key + (should-not (nettle-rsa-verify "Test the Nettle RSA signature" + "Test the Nettle RSA signature" + key-bitstring + "sha1")) + ;; valid signature, valid key + ; doesn't work; generated with "openssl rsautl -sign -in /tmp/test -inkey /tmp/privkey.pem" but contains other baggage + (should (nettle-rsa-verify "Test the Nettle RSA signature" + (decode-hex-string "abf710d920de0a210167e62995d5cb06fb0ff6a3f81e2f1965dd3f4716883ab61b7dec40d1ebde89b0657473a434d0333177f183f71a9f4b84a49781b1e4bc440e042f2eb4441000ba07168cdb190c5aebba8c433420f6fc28b6997cbfee061170210bfa65294199e6d6c8c5e1a16421942371f6115d77263b859a75645b6b70d56f14ad378c8499318ff05eda9d24a61d854a3d7f6b67b037abb8d25e4b11ca3e42bdb823cfac34c70057ecd55cbb8449346c0824b46f6c668d14f1744bad7d05470953981df32fde24d2a1f27e58bf9e7d99b20b39b25844c53945dcbbd8b406e78bc0b8aee48c0ec8a26e70301eeeb12ba733e0baf7b82c8e25ac3ee89291") + key-bitstring + "sha1")) +)) + +;; (message (encode-hex-string (nettle-pbkdf2 "password" "salt" 1 20 "sha1"))) + +(provide 'nettle) +;;; nettle.el ends here === modified file 'src/Makefile.in' --- src/Makefile.in 2013-09-15 17:58:46 +0000 +++ src/Makefile.in 2013-10-06 08:57:33 +0000 @@ -307,6 +307,9 @@ LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ +LIBNETTLE_LIBS = @LIBNETTLE_LIBS@ +LIBNETTLE_CFLAGS = @LIBNETTLE_CFLAGS@ + LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ INTERVALS_H = dispextern.h intervals.h composite.h @@ -349,7 +352,7 @@ $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) \ $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ - $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) \ + $(LIBGNUTLS_CFLAGS) $(LIBNETTLE_CFLAGS) $(GFILENOTIFY_CFLAGS) \ $(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS) ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS) @@ -373,7 +376,7 @@ alloc.o data.o doc.o editfns.o callint.o \ eval.o floatfns.o fns.o font.o print.o lread.o \ syntax.o $(UNEXEC_OBJ) bytecode.o \ - process.o gnutls.o callproc.o \ + process.o gnutls.o nettle.o callproc.o \ region-cache.o sound.o atimer.o \ doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \ profiler.o decompress.o \ @@ -430,7 +433,7 @@ $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ - $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \ + $(LIBGNUTLS_LIBS) $(LIBNETTLE_LIBS) $(LIB_PTHREAD) $(LIB_PTHREAD_SIGMASK) \ $(GFILENOTIFY_LIBS) $(LIB_MATH) $(LIBZ) all: emacs$(EXEEXT) $(OTHER_FILES) === modified file 'src/emacs.c' --- src/emacs.c 2013-09-20 15:34:36 +0000 +++ src/emacs.c 2013-10-06 08:57:33 +0000 @@ -84,6 +84,10 @@ #include "gnutls.h" #endif +#ifdef HAVE_NETTLE +#include "nettle.h" +#endif + #if (defined PROFILING \ && (defined __FreeBSD__ || defined GNU_LINUX || defined __MINGW32__)) # include @@ -1450,6 +1454,10 @@ syms_of_gnutls (); #endif +#ifdef HAVE_NETTLE + syms_of_nettle (); +#endif + #ifdef HAVE_GFILENOTIFY syms_of_gfilenotify (); #endif /* HAVE_GFILENOTIFY */ === added file 'src/nettle.c' --- src/nettle.c 1970-01-01 00:00:00 +0000 +++ src/nettle.c 2013-10-06 08:57:33 +0000 @@ -0,0 +1,505 @@ +/* libnettle+libhogweed glue for GNU Emacs. + Copyright (C) 2010-2013 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#include +#include + +#include "lisp.h" + +#ifdef HAVE_NETTLE + +#include "nettle.h" + +DEFUN ("nettle-available-p", Fnettle_available_p, Snettle_available_p, 0, 0, 0, + doc: /* Return t if libnettle+libhogweed are available in this instance of Emacs. */) + (void) +{ + return Qt; +} + +DEFUN ("nettle-hash", Fnettle_hash, Snettle_hash, 2, 2, 0, + doc: /* Hash INPUT string with HASH-METHOD into a unibyte string. + +The list of hash-methods can be obtained with `nettle-hashes`. +The `sha256' hashing method is recommended by the libnettle documentation. */) + (Lisp_Object input, Lisp_Object hash_method) +{ + Lisp_Object ret = Qnil; + + CHECK_STRING (input); + CHECK_STRING (hash_method); + + for (int i = 0; NULL != nettle_hashes[i]; i++) + { + if (0 == strcmp (SDATA (hash_method), nettle_hashes[i]->name)) + { + const struct nettle_hash *alg = nettle_hashes[i]; + unsigned int length = alg->digest_size; + void *ctx = xzalloc (alg->context_size); + uint8_t *digest; + ctx = xzalloc (alg->context_size); + alg->init (ctx); + alg->update (ctx, SCHARS (input), SDATA (input)); + + digest = xzalloc (length); + alg->digest (ctx, length, digest); + + ret = make_unibyte_string (digest, length); + + free (digest); + free (ctx); + } + } + + if (NILP (ret)) + { + error ("Nettle hash-method %s was not found", SDATA (hash_method)); + } + + return ret; +} + +DEFUN ("nettle-hmac", Fnettle_hmac, Snettle_hmac, 3, 3, 0, + doc: /* Hash INPUT string with HASH-METHOD and KEY into a unibyte string according to HMAC (RFC 2104). + +The list of hash-methods can be obtained with `nettle-hashes`. +The `sha256' hashing method is recommended by the libnettle documentation. */) + (Lisp_Object input, Lisp_Object key, Lisp_Object hash_method) +{ + Lisp_Object ret = Qnil; + + CHECK_STRING (input); + CHECK_STRING (hash_method); + CHECK_STRING (key); + + for (int i = 0; NULL != nettle_hashes[i]; i++) + { + if (0 == strcmp (SDATA (hash_method), nettle_hashes[i]->name)) + { + const struct nettle_hash *alg = nettle_hashes[i]; + unsigned int length = alg->digest_size; + void *inner_ctx = xzalloc (alg->context_size); + void *outer_ctx = xzalloc (alg->context_size); + void *state_ctx = xzalloc (alg->context_size); + uint8_t *digest; + + hmac_set_key (outer_ctx, inner_ctx, state_ctx, alg, SCHARS (key), SDATA (key)); + hmac_update (state_ctx, alg, SCHARS (input), SDATA (input)); + digest = xzalloc (length); + hmac_digest (outer_ctx, inner_ctx, state_ctx, alg, length, digest); + + ret = make_unibyte_string (digest, length); + + free (digest); + free (state_ctx); + free (outer_ctx); + free (inner_ctx); + } + } + + if (NILP (ret)) + { + error ("Nettle hash-method %s was not found", SDATA (hash_method)); + } + + return ret; +} + +DEFUN ("nettle-pbkdf2", Fnettle_pbkdf2, Snettle_pbkdf2, 5, 5, 0, + doc: /* Derive PBKDF2 of length HASH-LENGTH from KEY string with HASH-METHOD using ITERATIONS and SALT into a unibyte string according to RFC 2898. + +The list of hash-methods can be obtained with `nettle-hashes`. +The `sha1' and `sha256' hashing methods are most common and only supported now. */) + (Lisp_Object key, Lisp_Object salt, Lisp_Object iterations, Lisp_Object hash_length, Lisp_Object hash_method) +{ + Lisp_Object ret = Qnil; + bool sha1_mode = false; + bool sha256_mode = false; + int outlength = 0; + + CHECK_STRING (salt); + CHECK_STRING (hash_method); + CHECK_STRING (key); + CHECK_NUMBER (iterations); + CHECK_NUMBER (hash_length); + + outlength = XINT (hash_length); + + sha1_mode = 0 == strcmp (SDATA (hash_method), "sha1"); + sha256_mode = 0 == strcmp (SDATA (hash_method), "sha256"); + + if (sha1_mode) + { + uint8_t *digest = xzalloc (outlength); + pbkdf2_hmac_sha1 (SCHARS (key), SDATA (key), XINT (iterations), SCHARS (salt), SDATA (salt), outlength, digest); + ret = make_unibyte_string (digest, outlength); + free (digest); + } + else if (sha256_mode) + { + uint8_t *digest = xzalloc (outlength); + pbkdf2_hmac_sha256 (SCHARS (key), SDATA (key), XINT (iterations), SCHARS (salt), SDATA (salt), outlength, digest); + ret = make_unibyte_string (digest, outlength); + free (digest); + } + else + { + error ("Nettle hash-method %s is not supported yet, sorry", SDATA (hash_method)); + } + + /* TODO: figure out why this doesn't work correctly. For now only sha1 and sha256 are supported. + for (int i = 0; NULL != nettle_hashes[i]; i++) + { + if (0 == strcmp (SDATA (hash_method), nettle_hashes[i]->name)) + { + const struct nettle_hash *alg = nettle_hashes[i]; + unsigned int length = alg->digest_size; + void *ctx = NULL; + uint8_t *digest = xzalloc (outlength); + int csize = alg->context_size; + + message("Generating PBKDF2 with cipher %s, key(%d) '%s', salt(%d) '%s', iterations %d", alg->name, SCHARS (key), SDATA (key), SCHARS (salt), SDATA (salt), XINT (iterations)); + ctx = xzalloc (3*csize); + + // HMAC_SET_KEY(ctx, alg, SCHARS (key), SDATA (key)); + // PBKDF2 (ctx, alg->update, alg->digest, length, XINT (iterations), SCHARS (salt), SDATA (salt), outlength, digest); + message("first 4 bytes generated => %x %x %x %x", digest[0], digest[1], digest[2], digest[3] ); + + ret = make_unibyte_string (digest, outlength); + + free (digest); + free (ctx); + } + } + */ + + if (NILP (ret)) + { + error ("Nettle hash-method %s was not found", SDATA (hash_method)); + } + + return ret; +} + +DEFUN ("nettle-rsa-verify", Fnettle_rsa_verify, Snettle_rsa_verify, 4, 4, 0, + doc: /* Verify that the RSA SIGNATURE of DATA was created with PUBLIC-KEY according to HASH-METHOD. + +The list of hash-methods can be obtained with `nettle-hashes`. +Only the `md5', `sha1', `sha256', and `sha512' hashing methods are supported. */) + (Lisp_Object data, Lisp_Object signature, Lisp_Object public_key, Lisp_Object hash_method) +{ + Lisp_Object ret = Qnil; + bool md5_mode = false; + bool sha1_mode = false; + bool sha256_mode = false; + bool sha512_mode = false; + struct rsa_public_key key; + mpz_t s; + + CHECK_STRING (data); + CHECK_STRING (signature); + CHECK_STRING (public_key); + CHECK_STRING (hash_method); + + if (SCHARS (signature) < 16) + { + error ("RSA signature must be at least 16 bytes long"); + } + + mpz_init(s); + if (!mpz_set_str(s, SDATA (signature), 16)) + { + error ("RSA signature could not be loaded"); + } + + rsa_public_key_init(&key); + + if (!rsa_keypair_from_der (&key, NULL, 0, SCHARS (public_key), SDATA (public_key)) && + !rsa_keypair_from_sexp (&key, NULL, 0, SCHARS (public_key), SDATA (public_key))) + { + char* p = SDATA (public_key); + if (SCHARS (public_key) > 3) + { + // message("first 4 bytes of bad public key => %x %x %x %x", p[0], p[1], p[2], p[3] ); + } + error ("RSA public key could not be loaded in binary or DER formats"); + } + + md5_mode = 0 == strcmp (SDATA (hash_method), "md5"); + sha1_mode = 0 == strcmp (SDATA (hash_method), "sha1"); + sha256_mode = 0 == strcmp (SDATA (hash_method), "sha256"); + sha512_mode = 0 == strcmp (SDATA (hash_method), "sha512"); + + if (sha1_mode) + { + struct sha1_ctx hash; + + sha1_init(&hash); + sha1_update(&hash, SCHARS (data), SDATA (data)); + + if (rsa_sha1_verify(&key, &hash, s)) + { + ret = Qt; + } + } + else + { + error ("Nettle hash-method %s is not supported yet, sorry", SDATA (hash_method)); + } + + mpz_clear(s); + rsa_public_key_clear(&key); + + return ret; +} + +DEFUN ("nettle-hashes", Fnettle_hashes, Snettle_hashes, 0, 1, 0, + doc: /* Return alist of Nettle hash names and their digest and block sizes. +With the optional NAME, returns just one hash's info (NAME DIGESTSIZE BLOCKSIZE). */) + (Lisp_Object name) +{ + Lisp_Object hashes = Qnil; + + if (! NILP (name)) + { + CHECK_STRING (name); + } + + for (int i = 0; nettle_hashes[i] != NULL; i++) + { + Lisp_Object hash = Fcons (build_string (nettle_hashes[i]->name), + list2i (nettle_hashes[i]->digest_size, + nettle_hashes[i]->block_size)); + + if (! NILP (name) && 0 == strcmp (SDATA (name), nettle_hashes[i]->name)) + { + return hash; + } + + hashes = Fcons (hash, hashes); + } + + if (NILP (name)) + { + return hashes; + } + + return Qnil; +} + +DEFUN ("nettle-crypt", Fnettle_crypt, Snettle_crypt, 6, 6, 0, + doc: /* Encrypt or decrypt based on CRYPT-MODE INPUT string with unibyte KEY and CIPHER and CIPHER-MODE, seeding with IV, into a unibyte string. + +The INPUT will be zero-padded to be a multiple of the cipher's block size. + +The KEY will be zero-padded to the cipher's key size and will be +trimmed if it exceeds that key size. + +The list of ciphers can be obtained with `nettle-ciphers`. +The list of cipher modes can be obtained with `nettle-cipher-modes`. +The `aes256' cipher method is probably best for general use. +The `twofish256' cipher method may be better if you want to avoid NIST ciphers. */) + (Lisp_Object crypt_mode, Lisp_Object input, Lisp_Object key, Lisp_Object iv, Lisp_Object cipher, Lisp_Object cipher_mode) +{ + Lisp_Object ret = Qnil; + Lisp_Object mode = Qnil; + bool decrypt = NILP(crypt_mode); + bool ctr_mode = false; + + CHECK_STRING (input); + CHECK_SYMBOL (crypt_mode); + CHECK_STRING (key); + CHECK_STRING (iv); + CHECK_STRING (cipher); + CHECK_STRING (cipher_mode); + + mode = CAR_SAFE (Fmember (cipher_mode, Fnettle_cipher_modes ())); + + ctr_mode = 0 == strcmp (SDATA (mode), "CTR"); + + if (NILP (mode)) + { + error ("Nettle cipher mode %s was not found", SDATA (cipher_mode)); + } + + for (int i = 0; NULL != nettle_ciphers[i]; i++) + { + if (0 == strcmp (SDATA (cipher), nettle_ciphers[i]->name)) + { + const struct nettle_cipher *alg = nettle_ciphers[i]; + unsigned int input_length = SCHARS (input); + void *ctx = xzalloc (alg->context_size); + void *dest = NULL; + char *key_hold = NULL; + char *iv_hold = NULL; + + /* Increment input_length to the next multiple of block_size. */ + if (0 != alg->block_size) + { + while (0 != (input_length % alg->block_size)) + { + input_length++; + } + } + + // message("Input length is %d and the block size is %d", input_length, alg->block_size); + + dest = xzalloc (input_length); + memcpy (dest, SDATA (input), SCHARS (input)); + // message("Dest buffer: '%s' and size is %d", dest, input_length); + + key_hold = xzalloc (alg->key_size); + memcpy (key_hold, SDATA (key), min (alg->key_size, SCHARS (key))); + + iv_hold = xzalloc (alg->block_size); + memcpy (iv_hold, SDATA (iv), SCHARS (iv)); + + // message("Key buffer: '%s' and key size %d", key_hold, alg->key_size); + + // in CTR mode we use set_encrypt_key regardless + if (decrypt && !ctr_mode) + { + alg->set_decrypt_key (ctx, alg->key_size, key_hold); + } + else + { + alg->set_encrypt_key (ctx, alg->key_size, key_hold); + } + + // message("%s %s with cipher %s, key(%d) '%s', IV(%d) '%s', input(%d) '%s'", SDATA (mode), decrypt ? "decrypting" : "encrypting", alg->name, SCHARS (key), SDATA (key), SCHARS (iv), SDATA (iv), SCHARS (input), SDATA (input)); + if (0 == strcmp (SDATA (mode), "ECB")) + { + if (decrypt) + { + alg->decrypt (ctx, input_length, dest, dest); + } + else + { + alg->encrypt (ctx, input_length, dest, dest); + } + } + else if (0 == strcmp (SDATA (mode), "CBC")) + { + if (decrypt) + { + cbc_decrypt (ctx, alg->decrypt, + alg->block_size, iv_hold, + input_length, dest, dest); + } + else + { + cbc_encrypt (ctx, alg->encrypt, + alg->block_size, iv_hold, + input_length, dest, dest); + } + } + else if (ctr_mode) + { + ctr_crypt (ctx, alg->encrypt, + alg->block_size, iv_hold, + input_length, dest, dest); + } + else + { + error ("Unexpected error: Nettle cipher mode %s was not found", SDATA (mode)); + } + + // message("-> produced (%d) '%s'", input_length, dest); + ret = make_unibyte_string (dest, input_length); + + free (iv_hold); + free (key_hold); + free (dest); + free (ctx); + } + } + + if (NILP (ret)) + { + error ("Nettle cipher %s was not found", SDATA (cipher)); + } + + return ret; +} + +DEFUN ("nettle-ciphers", Fnettle_ciphers, Snettle_ciphers, 0, 1, 0, + doc: /* Return alist of Nettle cipher names and their key and block sizes. +With the optional NAME, returns just one cipher's info (NAME KEYSIZE BLOCKSIZE). */) + (Lisp_Object name) +{ + Lisp_Object ciphers = Qnil; + + if (! NILP (name)) + { + CHECK_STRING (name); + } + + for (int i = 0; nettle_ciphers[i] != NULL; i++) + { + Lisp_Object cipher = Fcons (build_string (nettle_ciphers[i]->name), + list2i (nettle_ciphers[i]->key_size, + nettle_ciphers[i]->block_size)); + + if (! NILP (name) && 0 == strcmp (SDATA (name), nettle_ciphers[i]->name)) + { + return cipher; + } + + ciphers = Fcons (cipher, ciphers); + } + + if (NILP (name)) + { + return ciphers; + } + + return Qnil; +} + +DEFUN ("nettle-cipher-modes", Fnettle_cipher_modes, Snettle_cipher_modes, 0, 0, 0, + doc: /* Return the list of Nettle cipher modes as strings. */) + (void) +{ + Lisp_Object modes = Qnil; + modes = Fcons (build_string ("ECB"), modes); + modes = Fcons (build_string ("CBC"), modes); + modes = Fcons (build_string ("CTR"), modes); + /* GCM is unsupported for now + modes = Fcons (build_string ("GCM"), modes); + */ + return modes; +} + +void +syms_of_nettle (void) +{ + defsubr (&Snettle_available_p); + defsubr (&Snettle_hash); + defsubr (&Snettle_hashes); + defsubr (&Snettle_crypt); + defsubr (&Snettle_ciphers); + defsubr (&Snettle_cipher_modes); + defsubr (&Snettle_rsa_verify); + // defsubr (&Snettle_dsa); + // defsubr (&Snettle_ecc); + defsubr (&Snettle_hmac); + defsubr (&Snettle_pbkdf2); + /* Not implemented yet. defsubr (&Snettle_umac); */ +} + +#endif /* HAVE_NETTLE */ === added file 'src/nettle.h' --- src/nettle.h 1970-01-01 00:00:00 +0000 +++ src/nettle.h 2013-10-06 08:57:33 +0000 @@ -0,0 +1,57 @@ +/* libnettle+libhogweed glue for GNU Emacs. + Copyright (C) 2010-2013 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#ifndef EMACS_NETTLE_DEFINED +#define EMACS_NETTLE_DEFINED + +#ifdef HAVE_NETTLE + +/* PGP protocol helpers. */ +#include + +/* Public-key crypto. */ +#include +#include +#include +#include + +#include + +/* Cipher modes. */ + +#include +#include +#include + +/* Keyed hash functions. */ +#include +#include + +/* Key derivation functions. */ + +#include + +/* Randomness functions. */ + +#include + +#endif + +extern void syms_of_nettle (void); + +#endif # Begin bundle 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