Add kdf_calc.py.
authorNIIBE Yutaka <gniibe@fsij.org>
Sat, 31 Mar 2018 01:28:54 +0000 (10:28 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 3 Apr 2018 08:17:20 +0000 (17:17 +0900)
NEWS
README
tool/gnuk_token.py
tool/kdf_calc.py [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 45d24ba..9f160b3 100644 (file)
--- 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 (file)
--- 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?
index 6d46b9c..bff9fa7 100644 (file)
@@ -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 <gniibe@fsij.org>
 
@@ -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 (file)
index 0000000..76b7b23
--- /dev/null
@@ -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 <gniibe@fsij.org>
+
+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 <http://www.gnu.org/licenses/>.
+"""
+
+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)