diff --git a/README.md b/README.md index ac8dbec..1f2910b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,51 @@ wincrypto ========= -Windows Crypto API compatible decryption/encryption for python +Windows Crypto API compatible decryption/encryption for python. The targeted crypto provider is PROV_RSA_AES. + +Implemented algorithms: + + - CALG_RC4 + - CALG_AES128 + - CALG_AES192 + - CALG_AES256 + - CALG_RSA_KEYX + - CALG_MD5 + - CALG_SHA1 + +Implemented functions: + + - CryptImportKey + - CryptExportKey + - CryptEncrypt + - CryptDecrypt + - CryptGetKeyParam (incomplete) + - CryptCreateHash + - CryptHashData + - CryptGetHashParam + - CryptDeriveKey + +An example of how to use this package: + +```python +from wincrypto import CryptCreateHash, CryptHashData, CryptDeriveKey, CryptEncrypt, CryptImportKey, CryptExportKey +from wincrypto.constants import CALG_SHA1, CALG_AES_256, bType_SIMPLEBLOB + +#derive key from password +sha1_hasher = CryptCreateHash(CALG_SHA1) +CryptHashData(sha1_hasher, 'Password') +aes_key = CryptDeriveKey(sha1_hasher, CALG_AES_256) + +#encrypt data using key +encrypted_data = CryptEncrypt(aes_key, 'secret data') + +#Import a PUBLICKEYBLOB and export the AES key as SIMPLEBLOB +TEST_RSA_PUBLIC_MSKEYBLOB = '0602000000a40000525341310004000001000100d1537575000617a37093cec958e8adedd347b5812f' \ + '702595fc02fbb870f6a17a26780f9147a6cd938dffff842a1427f8200621f822caaf9b338b4bb3dbda' \ + 'ce58eedfc7b29b91a1f5ce628657f30f3feb9d909a1a00bd484f628f2db38087eec2f6bb4df1df024b' \ + '19af1c97d316c86073c972059d65bc2b47f97e5462a2e8029a'.decode('hex') +rsa_pub_key = CryptImportKey(TEST_RSA_PUBLIC_MSKEYBLOB) +encrypted_aes_key = CryptExportKey(aes_key, rsa_pub_key, bType_SIMPLEBLOB) +``` [![Build Status](https://travis-ci.org/crappycrypto/wincrypto.png)](https://travis-ci.org/crappycrypto/wincrypto) \ No newline at end of file diff --git a/setup.py b/setup.py index 58e0876..a56a021 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup(name='wincrypto', - version='0.1a', + version='0.2a', description='Windows Crypto API compatible decryption/encryption', url='http://github.com/crappycrypto/wincrypto', author='crappycrypto', diff --git a/tests/algorithms.py b/tests/algorithms.py index 6c00c68..d3641f0 100644 --- a/tests/algorithms.py +++ b/tests/algorithms.py @@ -4,7 +4,7 @@ from wincrypto.algorithms import symmetric_algorithms, hash_algorithms from wincrypto.api import CryptImportKey, CryptExportKey, CryptCreateHash, CryptDeriveKey, \ CryptHashData -from wincrypto.definitions import bType_PLAINTEXTKEYBLOB, CALG_MD5, CALG_RC4, CALG_SHA1, CALG_AES_192 +from wincrypto.constants import bType_PLAINTEXTKEYBLOB, CALG_MD5, CALG_RC4, CALG_SHA1, CALG_AES_192, bType_SIMPLEBLOB TEST_RSA_PRIVATE_PEM = '''-----BEGIN RSA PRIVATE KEY----- @@ -45,7 +45,7 @@ def test_export_import_simple(self): rsa_key = wincrypto.algorithms.RSA_KEYX.from_pem(TEST_RSA_PRIVATE_PEM) for algorithm in symmetric_algorithms: instance = algorithm('A' * algorithm.key_len) - blob = CryptExportKey(instance, rsa_key, bType_PLAINTEXTKEYBLOB) + blob = CryptExportKey(instance, rsa_key, bType_SIMPLEBLOB) instance2 = CryptImportKey(blob, rsa_key) self.assertEqual(instance.key, instance2.key) diff --git a/tests/native.py b/tests/native.py index 5e55eea..cabb5d8 100644 --- a/tests/native.py +++ b/tests/native.py @@ -2,11 +2,11 @@ if platform.system() == 'Windows': import unittest - from wincrypto import native, definitions, api + from wincrypto import native, constants, api import wincrypto from wincrypto.algorithms import symmetric_algorithms, hash_algorithms import wincrypto.api - from wincrypto.definitions import bType_PLAINTEXTKEYBLOB, bType_SIMPLEBLOB, bType_PRIVATEKEYBLOB, KP_ALGID, \ + from wincrypto.constants import bType_PLAINTEXTKEYBLOB, bType_SIMPLEBLOB, bType_PRIVATEKEYBLOB, KP_ALGID, \ KP_KEYLEN, HP_HASHSIZE, HP_ALGID @@ -33,7 +33,10 @@ WMnOk3CjFwYAdXVT0QIDAQAB -----END PUBLIC KEY-----''' - TEST_RSA_PUBLIC_MSKEYBLOB = '\x06\x02\x00\x00\x00\xa4\x00\x00RSA1\x00\x04\x00\x00\x01\x00\x01\x00\xd1Suu\x00\x06\x17\xa3p\x93\xce\xc9X\xe8\xad\xed\xd3G\xb5\x81/p%\x95\xfc\x02\xfb\xb8p\xf6\xa1z&x\x0f\x91G\xa6\xcd\x93\x8d\xff\xff\x84*\x14\'\xf8 \x06!\xf8"\xca\xaf\x9b3\x8bK\xb3\xdb\xda\xceX\xee\xdf\xc7\xb2\x9b\x91\xa1\xf5\xceb\x86W\xf3\x0f?\xeb\x9d\x90\x9a\x1a\x00\xbdHOb\x8f-\xb3\x80\x87\xee\xc2\xf6\xbbM\xf1\xdf\x02K\x19\xaf\x1c\x97\xd3\x16\xc8`s\xc9r\x05\x9de\xbc+G\xf9~Tb\xa2\xe8\x02\x9a' + TEST_RSA_PUBLIC_MSKEYBLOB = '0602000000a40000525341310004000001000100d1537575000617a37093cec958e8adedd347b5812f' \ + '702595fc02fbb870f6a17a26780f9147a6cd938dffff842a1427f8200621f822caaf9b338b4bb3dbda' \ + 'ce58eedfc7b29b91a1f5ce628657f30f3feb9d909a1a00bd484f628f2db38087eec2f6bb4df1df024b' \ + '19af1c97d316c86073c972059d65bc2b47f97e5462a2e8029a'.decode('hex') TEST_RSA_PRIVATE_MSKEYBLOB = '\x07\x02\x00\x00\x00\xa4\x00\x00RSA2\x00\x04\x00\x00\x01\x00\x01\x00\xd1Suu\x00\x06\x17\xa3p\x93\xce\xc9X\xe8\xad\xed\xd3G\xb5\x81/p%\x95\xfc\x02\xfb\xb8p\xf6\xa1z&x\x0f\x91G\xa6\xcd\x93\x8d\xff\xff\x84*\x14\'\xf8 \x06!\xf8"\xca\xaf\x9b3\x8bK\xb3\xdb\xda\xceX\xee\xdf\xc7\xb2\x9b\x91\xa1\xf5\xceb\x86W\xf3\x0f?\xeb\x9d\x90\x9a\x1a\x00\xbdHOb\x8f-\xb3\x80\x87\xee\xc2\xf6\xbbM\xf1\xdf\x02K\x19\xaf\x1c\x97\xd3\x16\xc8`s\xc9r\x05\x9de\xbc+G\xf9~Tb\xa2\xe8\x02\x9a\x9b\\tcH\x8aa\x01\xac\x9b\x12\x11\x8f\xc6i\x8bb\xf6XoJ{\xf9uW\x15\xcc[\x01P\xdd\x86\xd9L\xbb\xa2\x13\xc3{\xa0\xf5\xe1K\x86:\xa01h\xf4\x1a\x89\xbd?\xd4J\xc2\xc5\x9f\x9by\x9a\xb6J\xb5\x03\x9a\xd9$1U\xff\x069\x0e\x1c\xf2\xf3\xcf\x8b;\xd6\x9e%\xca\xcd\xa5\xa5\xd6\x96\xc3)E\xba\x0b\xbe\xeb9\xa2\xb4*\xffw\xb8\xf3\xc9%\x0f}\xcc\xfb\x13\x83WL\xf8\x9fh\x10_D\xde\xf2w\xe3LAz\xd9\xebc?\xc9\xf64\xbb\xea\xa4\xc2@\xfd\xf2\x1b\x04J\r\xaa\x13\x93%\x1cxD\xd6\xdc\xddl\xbb\xb1An^\x83\xe3\xdf\x15\x9f\xa9\x11\x98e-\xd1\x8f\x1c\x8fIBB\xbd\x89\x91<\xba\x12^\x85\x8a\xb3]\xcfh\xae\r~\x07lcD3\x9a9\xe7\xb5\'\xe0e1\xb6\x1c\x93\xe1\xc4+\xf4\xe51b\xf8\xed\x15\xf7h\xaa\x00\xc0]\x17^\xbd\x13\x8d\x0f\xc3\xf7E\xa6\xb8\x83\xe4`\x04\n\x80O\x90A\xe8N{~\x88\xc8\xac\xaf\x03`\x0b\x00\xff\\A\x16\xba\x86|n\x89a\xa4P\x0e\x042\xd5\xe8\xa5\xa6\x9a\x15}?Q\x08\x8e\x83I\x89\x97\xa2n\xb8X\xf4\x16D>q\x1d\xac;\x05\x8c\xc3\x8c\x18\x842\xa2]}h3D\xb8c\xf3\x14\x9aE\x949\x87\xbf\xf1P\xef\x81\xf5=\x80\xdb\xdd\x7f\xe8\xfb2J\xa7\xbc\x8a\xd6PK\x184\x07\xfd\xc0\x93\xaf\rW\xd7\x0c\xcc\x15\x7f\x19*\xd0}\x82\xdai\xaf\xa88\x86N\xbe\xaew\xa1\x97\x1coI\x16\xd4\xfb\xf1R\xce\xa8\x8eUX\xbd\x1f\x93:\x9b*\xa3p(\xdf\xc6u\xd5Rip\xa0\xfe\xd8\xebCsV:p\xc7\t\t\x06\x82i\x14\xa5\xda\xa5#-\xd5\xbb\x08(kW\xd3\xf2xM\xfa\xb7\xdf[\x1a\x1aR\xfc7\xa0\xd6\x990B' TEST_DATA = str(bytearray(range(64))) # 64 is a multiple of most blocksizes @@ -62,7 +65,7 @@ def test_native_simplekeyblob(self): rsa_hkey = native.CryptImportKey(self.hprov, rsa_blob) for algorithm in symmetric_algorithms: instance = algorithm('A' * algorithm.key_len) - blob = wincrypto.api.CryptExportKey(instance, rsa_key.key, bType_SIMPLEBLOB) + blob = wincrypto.api.CryptExportKey(instance, rsa_key, bType_SIMPLEBLOB) hkey = native.CryptImportKey(self.hprov, blob, rsa_hkey) c = native.CryptEncrypt(hkey, TEST_DATA) p = instance.decrypt(c) @@ -118,14 +121,14 @@ def test_hash_native_python(self): for algorithm in hash_algorithms: hCryptHash = native.CryptCreateHash(self.hprov, algorithm.alg_id) native.CryptHashData(hCryptHash, TEST_DATA) - native_hash_val = native.CryptGetHashParam(hCryptHash, definitions.HP_HASHVAL) + native_hash_val = native.CryptGetHashParam(hCryptHash, constants.HP_HASHVAL) native_hash_size = native.CryptGetHashParam(hCryptHash, HP_HASHSIZE) native_hash_algid = native.CryptGetHashParam(hCryptHash, HP_ALGID) native.CryptDestroyHash(hCryptHash) md5_hash = wincrypto.api.CryptCreateHash(algorithm.alg_id) wincrypto.api.CryptHashData(md5_hash, TEST_DATA) - python_hash = wincrypto.api.CryptGetHashParam(md5_hash, definitions.HP_HASHVAL) + python_hash = wincrypto.api.CryptGetHashParam(md5_hash, constants.HP_HASHVAL) python_hash_size = wincrypto.api.CryptGetHashParam(md5_hash, HP_HASHSIZE) python_hash_algid = wincrypto.api.CryptGetHashParam(md5_hash, HP_ALGID) diff --git a/wincrypto/algorithms.py b/wincrypto/algorithms.py index 79a46fe..038ef70 100644 --- a/wincrypto/algorithms.py +++ b/wincrypto/algorithms.py @@ -8,10 +8,11 @@ from Crypto.PublicKey import RSA from Crypto.Util.number import long_to_bytes, bytes_to_long, inverse -from wincrypto.definitions import RSAPUBKEY, RSAPUBKEY_s, RSAPUBKEY_MAGIC, PUBLICKEYSTRUC_s, bType_PUBLICKEYBLOB, \ +from wincrypto.constants import RSAPUBKEY, RSAPUBKEY_s, RSAPUBKEY_MAGIC, PUBLICKEYSTRUC_s, bType_PUBLICKEYBLOB, \ CUR_BLOB_VERSION, CALG_RSA_KEYX, PRIVATEKEYBLOB_MAGIC, PRIVATEKEYBLOB, bType_PRIVATEKEYBLOB, bType_PLAINTEXTKEYBLOB, \ - bType_SIMPLEBLOB, CALG_RC4, CALG_AES_128, CALG_AES_192, CALG_AES_256, CALG_MD5, CALG_SHA1 -from wincrypto.util import add_pkcs5_padding, remove_pkcs5_padding + bType_SIMPLEBLOB, CALG_RC4, CALG_AES_128, CALG_AES_192, CALG_AES_256, CALG_MD5, CALG_SHA1, ALG_CLASS_HASH, \ + ALG_CLASS_KEY_EXCHANGE, ALG_CLASS_DATA_ENCRYPT +from wincrypto.util import add_pkcs5_padding, remove_pkcs5_padding, GET_ALG_CLASS class HCryptKey(object): @@ -120,17 +121,15 @@ def export_plaintextkeyblob(self): def import_simpleblob(cls, data, hPubKey): assert struct.unpack('