From 3ade3d8a417cab9e0bde88ee7b10cf6bce2df7c1 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 15 Dec 2015 19:48:40 +0100 Subject: [PATCH] use hashlib.pbkdf2_hmac from py stdlib instead of own openssl wrapper this is available in python 3.4+. note: before removing the pbkdf tests, i ran them with the pbkdf from stdlib to make sure it gives same result. long term testing of this now belongs into stdlib tests, not into borg. --- borg/crypto.pyx | 23 +---------------------- borg/key.py | 6 +++--- borg/testsuite/crypto.py | 10 +--------- 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/borg/crypto.pyx b/borg/crypto.pyx index d8143bdbc..199ffbaf8 100644 --- a/borg/crypto.pyx +++ b/borg/crypto.pyx @@ -1,7 +1,6 @@ """A thin OpenSSL wrapper -This could be replaced by PyCrypto or something similar when the performance -of their PBKDF2 implementation is comparable to the OpenSSL version. +This could be replaced by PyCrypto maybe? """ from libc.stdlib cimport malloc, free @@ -21,7 +20,6 @@ cdef extern from "openssl/evp.h": pass ctypedef struct ENGINE: pass - const EVP_MD *EVP_sha256() const EVP_CIPHER *EVP_aes_256_ctr() void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a) void EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a) @@ -37,10 +35,6 @@ cdef extern from "openssl/evp.h": int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) - int PKCS5_PBKDF2_HMAC(const char *password, int passwordlen, - const unsigned char *salt, int saltlen, int iter, - const EVP_MD *digest, - int keylen, unsigned char *out) import struct @@ -59,21 +53,6 @@ def num_aes_blocks(int length): return (length + 15) // 16 -def pbkdf2_sha256(password, salt, iterations, size): - """Password based key derivation function 2 (RFC2898) - """ - cdef unsigned char *key = malloc(size) - if not key: - raise MemoryError - try: - rv = PKCS5_PBKDF2_HMAC(password, len(password), salt, len(salt), iterations, EVP_sha256(), size, key) - if not rv: - raise Exception('PKCS5_PBKDF2_HMAC failed') - return key[:size] - finally: - free(key) - - def get_random_bytes(n): """Return n cryptographically strong pseudo-random bytes """ diff --git a/borg/key.py b/borg/key.py index 97a8dca54..fe3b1d5a4 100644 --- a/borg/key.py +++ b/borg/key.py @@ -5,13 +5,13 @@ import os import sys import textwrap from hmac import HMAC, compare_digest -from hashlib import sha256 +from hashlib import sha256, pbkdf2_hmac from .helpers import IntegrityError, get_keys_dir, Error from .logger import create_logger logger = create_logger() -from .crypto import pbkdf2_sha256, get_random_bytes, AES, bytes_to_long, long_to_bytes, bytes_to_int, num_aes_blocks +from .crypto import get_random_bytes, AES, bytes_to_long, long_to_bytes, bytes_to_int, num_aes_blocks from .compress import Compressor, COMPR_BUFFER import msgpack @@ -199,7 +199,7 @@ class Passphrase(str): return '' def kdf(self, salt, iterations, length): - return pbkdf2_sha256(self.encode('utf-8'), salt, iterations, length) + return pbkdf2_hmac('sha256', self.encode('utf-8'), salt, iterations, length) class PassphraseKey(AESKeyBase): diff --git a/borg/testsuite/crypto.py b/borg/testsuite/crypto.py index e438eb85e..e8f56515d 100644 --- a/borg/testsuite/crypto.py +++ b/borg/testsuite/crypto.py @@ -1,6 +1,6 @@ from binascii import hexlify -from ..crypto import AES, bytes_to_long, bytes_to_int, long_to_bytes, pbkdf2_sha256, get_random_bytes +from ..crypto import AES, bytes_to_long, bytes_to_int, long_to_bytes, get_random_bytes from . import BaseTestCase @@ -13,14 +13,6 @@ class CryptoTestCase(BaseTestCase): self.assert_equal(bytes_to_long(b'\0\0\0\0\0\0\0\1'), 1) self.assert_equal(long_to_bytes(1), b'\0\0\0\0\0\0\0\1') - def test_pbkdf2_sha256(self): - self.assert_equal(hexlify(pbkdf2_sha256(b'password', b'salt', 1, 32)), - b'120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b') - self.assert_equal(hexlify(pbkdf2_sha256(b'password', b'salt', 2, 32)), - b'ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43') - self.assert_equal(hexlify(pbkdf2_sha256(b'password', b'salt', 4096, 32)), - b'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a') - def test_get_random_bytes(self): bytes = get_random_bytes(10) bytes2 = get_random_bytes(10)