import binascii
import ctypes
import io
-from functools import reduce
+from functools import reduce, partial
import os
import struct
import sys
###############################################################################
ENCRYPTION_PARAMETERS = \
- { 1: \
+ { 0: \
+ { "kdf": ("dummy", 16) }
+ , 1: \
{ "kdf": ("scrypt",
{ "dkLen" : 16
, "N" : 1 << 15
AES_GCM_MAX_SIZE = (1 << 36) - (1 << 5) # 2^39 - 2^8 b ≅ 64 GB
AES_GCM_FMT_TAG = "<16s"
-# scrypt
-SCRYPT_dkLen = 16
-SCRYPT_N = 1 << 15
-SCRYPT_r = 8
-SCRYPT_p = 1
-SCRYPT_NaCl_LEN = 16
-
###############################################################################
## header, trailer
## convenience wrapper
###############################################################################
-KEY_MEMO = { } # static because needed for both the info file and the archive
+
+def kdf_dummy (klen, password, _nacl):
+ q, r = divmod (klen, len (password))
+ if isinstance (password, bytes) is False:
+ password = password.encode ()
+ return password * q + password [:r], b""
+
+
+SCRYPT_KEY_MEMO = { } # static because needed for both the info file and the archive
+
+
+def kdf_scrypt (params, password, nacl):
+ N = params["N"]
+ r = params["r"]
+ p = params["p"]
+ dkLen = params["dkLen"]
+
+ if nacl is None:
+ nacl = os.urandom (params["NaCl_LEN"])
+
+ key_parms = (password, nacl, N, r, p, dkLen)
+ global SCRYPT_KEY_MEMO
+ if key_parms not in SCRYPT_KEY_MEMO:
+ SCRYPT_KEY_MEMO [key_parms] = \
+ pylibscrypt.scrypt (password, nacl, N, r, p, dkLen)
+ return SCRYPT_KEY_MEMO [key_parms], nacl
def kdf_by_version (paramversion):
raise ValueError ("no encryption parameters for version %r"
% paramversion)
(kdf, params) = defs["kdf"]
- if kdf != "scrypt":
+ fn = None
+ if kdf == "scrypt" : fn = kdf_scrypt
+ if kdf == "dummy" : fn = kdf_dummy
+ if fn is None:
raise ValueError ("key derivation method %r unknown" % kdf)
- return kdf, params
+ return partial (fn, params)
self.set_parameters (*al, **akv)
- def set_parameters (self, password, paramversion, nacl, pfx=None):
+ def set_parameters (self, password, paramversion, nacl=None, pfx=None):
if isinstance (password, bytes) is False: password = str.encode (password)
self.password = password
self.nacl = nacl
self.paramversion = paramversion
- (kdf, params) = kdf_by_version (paramversion)
-
- N = params["N"]
- r = params["r"]
- p = params["p"]
- dkLen = params["dkLen"]
-
- key_parms = (password, nacl, N, r, p, dkLen)
- global KEY_MEMO
- if key_parms not in KEY_MEMO:
- KEY_MEMO [key_parms] = pylibscrypt.scrypt (password, nacl, N, r, p, dkLen)
- self.key = KEY_MEMO [key_parms]
+ kdf = kdf_by_version (paramversion)
+ if kdf is not None:
+ self.key, self.nacl = kdf (password, nacl)
if pfx is not None:
self.pfx = pfx
ctsize = -1 # per object from .next() → .done()
def __init__ (self, password, paramversion, nacl=None):
- if nacl is None:
- _, params = kdf_by_version (paramversion)
- nacl = os.urandom (params["NaCl_LEN"])
super().__init__ (password, paramversion, nacl)
def next (self, filename, version, paramversion, nacl):
self.iv = self.iv_make()
- self.curobj = (filename, version, paramversion, nacl)
+ self.curobj = (filename, version, paramversion, nacl or self.nacl)
self.cnt += 1
self.ctsize = 0
self.aes = Cipher \