From d71b116be80177dd24d001e4bf9473623efdaab4 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Sat, 31 Mar 2018 10:28:54 +0900 Subject: [PATCH] Add kdf_calc.py. --- NEWS | 13 +++++++++++++ README | 10 +++++----- tool/gnuk_token.py | 47 +++++++++++++++++++++++++++++++++++++++++++++- tool/kdf_calc.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 tool/kdf_calc.py diff --git a/NEWS b/NEWS index 45d24ba..9f160b3 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,18 @@ Gnuk NEWS - User visible changes +* Major changes in Gnuk 1.2.9 + + Released 2018-03-31, by NIIBE Yutaka + +** Add "single-salt" support for KDF-DO +With KDF-DO, "admin-less" mode didn't work well. With new feature of +"single-salt" support, we can use "admin-less" mode with KDF-DO. + +** factory-reset deletes all upgrade public keys +By card-edit/factory-reset by GnuPG, it deletes all upgrade public +keys, now. + + * Major changes in Gnuk 1.2.8 Released 2018-01-23, by NIIBE Yutaka diff --git a/README b/README index d3c96d4..f0baa4b 100644 --- a/README +++ b/README @@ -1,14 +1,14 @@ Gnuk - An Implementation of USB Cryptographic Token for GnuPG - Version 1.2.8 - 2018-01-23 + Version 1.2.9 + 2018-03-31 Niibe Yutaka Free Software Initiative of Japan Release Notes ============= -This is the release of Gnuk, version 1.2.8, which has major +This is the release of Gnuk, version 1.2.9, which has major incompatible changes to Gnuk 1.0.x. Specifically, it now supports overriding key import, but importing keys (or generating keys) results password reset. Also, you need to import private keys before changing @@ -25,9 +25,9 @@ than 8 seconds to sign/decrypt. Key generation of RSA-4096 just fails, because the device doesn't have enough memory. It supports new KDF-DO feature. To use the feature, you need to use -newer GnuPG (forthcoming 2.2.5 or later). And you need to manually +newer GnuPG (forthcoming 2.2.6 or later). And you need to manually prepare the KDF-DO on your token. Please note that this is -experimental. Better way to prepare KDF-DO will be expected. +experimental. GnuPG 2.2.6 will include KDF-DO setup. What's Gnuk? diff --git a/tool/gnuk_token.py b/tool/gnuk_token.py index 6d46b9c..bff9fa7 100644 --- a/tool/gnuk_token.py +++ b/tool/gnuk_token.py @@ -1,7 +1,7 @@ """ gnuk_token.py - a library for Gnuk Token -Copyright (C) 2011, 2012, 2013, 2015, 2017 +Copyright (C) 2011, 2012, 2013, 2015, 2017, 2018 Free Software Initiative of Japan Author: NIIBE Yutaka @@ -635,3 +635,48 @@ def UNSIGNED(n): def crc32(bytestr): crc = binascii.crc32(bytestr) return UNSIGNED(crc) + +def parse_kdf_data(kdf_data): + if len(kdf_data) == 90: + single_salt = True + elif len(kdf_data) == 110: + single_salt = False + else: + raise ValueError("length does not much") + + if kdf_data[0:2] != b'\x81\x01': + raise ValueError("data does not much") + algo = kdf_data[2] + if kdf_data[3:5] != b'\x82\x01': + raise ValueError("data does not much") + subalgo = kdf_data[5] + if kdf_data[6:8] != b'\x83\x04': + raise ValueError("data does not much") + iters = unpack(">I", kdf_data[8:12])[0] + if kdf_data[12:14] != b'\x84\x08': + raise ValueError("data does not much") + salt = kdf_data[14:22] + if single_salt: + salt_reset = None + salt_admin = None + if kdf_data[22:24] != b'\x87\x20': + raise ValueError("data does not much") + hash_user = kdf_data[24:56] + if kdf_data[56:58] != b'\x88\x20': + raise ValueError("data does not much") + hash_admin = kdf_data[58:90] + else: + if kdf_data[22:24] != b'\x85\x08': + raise ValueError("data does not much") + salt_reset = kdf_data[24:32] + if kdf_data[32:34] != b'\x86\x08': + raise ValueError("data does not much") + salt_admin = kdf_data[34:42] + if kdf_data[42:44] != b'\x87\x20': + raise ValueError("data does not much") + hash_user = kdf_data[44:76] + if kdf_data[76:78] != b'\x88\x20': + raise ValueError("data does not much") + hash_admin = kdf_data[78:110] + return ( algo, subalgo, iters, salt, salt_reset, salt_admin, + hash_user, hash_admin ) diff --git a/tool/kdf_calc.py b/tool/kdf_calc.py new file mode 100644 index 0000000..76b7b23 --- /dev/null +++ b/tool/kdf_calc.py @@ -0,0 +1,47 @@ +""" +kdf_calc.py - a library for calculating hash by KDF + +Copyright (C) 2018 Free Software Initiative of Japan +Author: NIIBE Yutaka + +This file is a part of Gnuk, a GnuPG USB Token implementation. + +Gnuk 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. + +Gnuk 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 . +""" + +from cffi import FFI + +DEF_gcry_kdf_derive=""" +typedef unsigned int gpg_error_t; +gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen, + int algo, int subalgo, const void *salt, + size_t saltlen, unsigned long iterations, + size_t keysize, void *keybuffer); +""" + +GCRY_KDF_ITERSALTED_S2K = 19 +GCRY_MD_SHA256 = 8 + +def kdf_calc(pw_string, salt_byte, iterations): + ffi = FFI() + ffi.cdef(DEF_gcry_kdf_derive) + libgcrypt = ffi.dlopen("libgcrypt.so") + pw=ffi.new("char []", pw_string.encode('UTF-8')) + salt = ffi.new("char []", salt_byte) + kb = ffi.new("char []", 32) + r = libgcrypt.gcry_kdf_derive(pw, len(pw_string), GCRY_KDF_ITERSALTED_S2K, + GCRY_MD_SHA256, salt, 8, iterations, 32, kb) + if r != 0: + raise ValueError("libgcrypt error", r) + return ffi.string(kb)