From a1e089149637c673061bb66d7e20b24200f1cc91 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Wed, 26 Dec 2018 15:43:46 +0100 Subject: [PATCH 01/12] * encrypt module importing moved to new api module, as there is problem while installing this product in virtualenv because of cryptography and asn1crypto dependencies. * python2/3 compatiblity added in encrypt module * pipenv introduced for development for easy package management * tests are made pass due to recent changes --- Pipfile | 19 ++ Pipfile.lock | 443 +++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- smime/__init__.py | 1 - smime/api.py | 2 + smime/encrypt.py | 29 +-- smime/encrypt_test.py | 15 +- smime/print_util_test.py | 4 +- 8 files changed, 489 insertions(+), 26 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 smime/api.py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..d47827d --- /dev/null +++ b/Pipfile @@ -0,0 +1,19 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] +smime = {path = ".",extras = ["test"],editable = true} + +[packages] +cryptography = "*" +asn1crypto = "*" +flake8 = "*" +flake8-isort = "*" +isort = "*" +certifi = "*" +zest-releaser = {extras = ["recommended"],version = "*"} + +[requires] +python_version = "2.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..2a835ec --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,443 @@ +{ + "_meta": { + "hash": { + "sha256": "b36f3decc7aeac80e00d889956f045be3728233494e6b8e6a605b413d7f9d67b" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "2.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "asn1crypto": { + "hashes": [ + "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", + "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" + ], + "index": "pypi", + "version": "==0.24.0" + }, + "bleach": { + "hashes": [ + "sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718", + "sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9" + ], + "version": "==3.0.2" + }, + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "index": "pypi", + "version": "==2018.11.29" + }, + "cffi": { + "hashes": [ + "sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743", + "sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef", + "sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50", + "sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f", + "sha256:3bb6bd7266598f318063e584378b8e27c67de998a43362e8fce664c54ee52d30", + "sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93", + "sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257", + "sha256:495c5c2d43bf6cebe0178eb3e88f9c4aa48d8934aa6e3cddb865c058da76756b", + "sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3", + "sha256:57b2533356cb2d8fac1555815929f7f5f14d68ac77b085d2326b571310f34f6e", + "sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc", + "sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04", + "sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6", + "sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359", + "sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596", + "sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b", + "sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd", + "sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95", + "sha256:a6a5cb8809091ec9ac03edde9304b3ad82ad4466333432b16d78ef40e0cce0d5", + "sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e", + "sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6", + "sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca", + "sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31", + "sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1", + "sha256:ca1bd81f40adc59011f58159e4aa6445fc585a32bb8ac9badf7a2c1aa23822f2", + "sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085", + "sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801", + "sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4", + "sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184", + "sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917", + "sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f", + "sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb" + ], + "version": "==1.11.5" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "check-manifest": { + "hashes": [ + "sha256:44e3cf4b0833a55460046bf7a3600eaadbcae5e9d13baf0c9d9789dd5c2c6452", + "sha256:728edbaccadaa86db0b8f876afac1fb90bce9452234753dfe4ef8fe786dcc2f1" + ], + "version": "==0.37" + }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "version": "==0.4.1" + }, + "configparser": { + "hashes": [ + "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a" + ], + "markers": "python_version < '3.2'", + "version": "==3.5.0" + }, + "cryptography": { + "hashes": [ + "sha256:05a6052c6a9f17ff78ba78f8e6eb1d777d25db3b763343a1ae89a7a8670386dd", + "sha256:0eb83a24c650a36f68e31a6d0a70f7ad9c358fa2506dc7b683398b92e354a038", + "sha256:0ff4a3d6ea86aa0c9e06e92a9f986de7ee8231f36c4da1b31c61a7e692ef3378", + "sha256:1699f3e916981df32afdd014fb3164db28cdb61c757029f502cb0a8c29b2fdb3", + "sha256:1b1f136d74f411f587b07c076149c4436a169dc19532e587460d9ced24adcc13", + "sha256:21e63dd20f5e5455e8b34179ac43d95b3fb1ffa54d071fd2ed5d67da82cfe6dc", + "sha256:2454ada8209bbde97065453a6ca488884bbb263e623d35ba183821317a58b46f", + "sha256:3cdc5f7ca057b2214ce4569e01b0f368b3de9d8ee01887557755ccd1c15d9427", + "sha256:418e7a5ec02a7056d3a4f0c0e7ea81df374205f25f4720bb0e84189aa5fd2515", + "sha256:471a097076a7c4ab85561d7fa9a1239bd2ae1f9fd0047520f13d8b340bf3210b", + "sha256:5ecaf9e7db3ca582c6de6229525d35db8a4e59dc3e8a40a331674ed90e658cbf", + "sha256:63b064a074f8dc61be81449796e2c3f4e308b6eba04a241a5c9f2d05e882c681", + "sha256:6afe324dfe6074822ccd56d80420df750e19ac30a4e56c925746c735cf22ae8b", + "sha256:70596e90398574b77929cd87e1ac6e43edd0e29ba01e1365fed9c26bde295aa5", + "sha256:70c2b04e905d3f72e2ba12c58a590817128dfca08949173faa19a42c824efa0b", + "sha256:8908f1db90be48b060888e9c96a0dee9d842765ce9594ff6a23da61086116bb6", + "sha256:af12dfc9874ac27ebe57fc28c8df0e8afa11f2a1025566476b0d50cdb8884f70", + "sha256:b4fc04326b2d259ddd59ed8ea20405d2e695486ab4c5e1e49b025c484845206e", + "sha256:da5b5dda4aa0d5e2b758cc8dfc67f8d4212e88ea9caad5f61ba132f948bab859" + ], + "index": "pypi", + "version": "==2.4.2" + }, + "docutils": { + "hashes": [ + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + ], + "version": "==0.14" + }, + "enum34": { + "hashes": [ + "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", + "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", + "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", + "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" + ], + "markers": "python_version < '3'", + "version": "==1.1.6" + }, + "flake8": { + "hashes": [ + "sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670", + "sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2" + ], + "index": "pypi", + "version": "==3.6.0" + }, + "flake8-isort": { + "hashes": [ + "sha256:3c107c405dd6e3dbdcccb2f84549d76d58a07120cd997a0560fab8b84c305f2a", + "sha256:76d7dd6aec2762c608b442abebb0aaedb72fc75f9a075241a89e4784d8a39900" + ], + "index": "pypi", + "version": "==2.6.0" + }, + "futures": { + "hashes": [ + "sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265", + "sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1" + ], + "version": "==3.2.0" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "ipaddress": { + "hashes": [ + "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", + "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" + ], + "markers": "python_version < '3'", + "version": "==1.0.22" + }, + "isort": { + "hashes": [ + "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", + "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", + "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" + ], + "index": "pypi", + "version": "==4.3.4" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pkginfo": { + "hashes": [ + "sha256:5878d542a4b3f237e359926384f1dde4e099c9f5525d236b1840cf704fa8d474", + "sha256:a39076cb3eb34c333a0dd390b568e9e1e881c7bf2cc0aee12120636816f55aee" + ], + "version": "==1.4.2" + }, + "pycodestyle": { + "hashes": [ + "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", + "sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" + ], + "version": "==2.4.0" + }, + "pycparser": { + "hashes": [ + "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" + ], + "version": "==2.19" + }, + "pyflakes": { + "hashes": [ + "sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49", + "sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae" + ], + "version": "==2.0.0" + }, + "pygments": { + "hashes": [ + "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", + "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" + ], + "version": "==2.3.1" + }, + "pyroma": { + "hashes": [ + "sha256:3ed770a0ed1616ee2ffa576852e34fb1ea5b54c37ff78dd33cff67d0e4bb584b", + "sha256:94a11cb077976bff9bd37ac8b487902556f216c4ee90b74a2344367f73b6ee7f" + ], + "version": "==2.4" + }, + "readme-renderer": { + "hashes": [ + "sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f", + "sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d" + ], + "version": "==24.0" + }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "version": "==2.21.0" + }, + "requests-toolbelt": { + "hashes": [ + "sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237", + "sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5" + ], + "version": "==0.8.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "testfixtures": { + "hashes": [ + "sha256:1e0affc9b459f039ebf9ae6e8af4059ded4d293863d4af9ffcd83e3b5e8df9cc", + "sha256:b040b59e0089809c2f157d3463ea288a10d890661695581649f40ae967944829" + ], + "version": "==6.4.1" + }, + "tqdm": { + "hashes": [ + "sha256:3c4d4a5a41ef162dd61f1edb86b0e1c7859054ab656b2e7c7b77e7fbf6d9f392", + "sha256:5b4d5549984503050883bc126280b386f5f4ca87e6c023c5d015655ad75bdebb" + ], + "version": "==4.28.1" + }, + "twine": { + "hashes": [ + "sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c", + "sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c" + ], + "version": "==1.12.1" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, + "wheel": { + "hashes": [ + "sha256:029703bf514e16c8271c3821806a1c171220cc5bdd325cbf4e7da1e056a01db6", + "sha256:1e53cdb3f808d5ccd0df57f964263752aa74ea7359526d3da6c02114ec1e1d44" + ], + "version": "==0.32.3" + }, + "zest-releaser": { + "extras": [ + "recommended" + ], + "hashes": [ + "sha256:64bcf954c5a7327cce7d402fc97f616369272c74fabf2b6b34b7a63a743e2d70" + ], + "index": "pypi", + "version": "==6.15.3" + } + }, + "develop": { + "asn1crypto": { + "hashes": [ + "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", + "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" + ], + "index": "pypi", + "version": "==0.24.0" + }, + "cffi": { + "hashes": [ + "sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743", + "sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef", + "sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50", + "sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f", + "sha256:3bb6bd7266598f318063e584378b8e27c67de998a43362e8fce664c54ee52d30", + "sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93", + "sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257", + "sha256:495c5c2d43bf6cebe0178eb3e88f9c4aa48d8934aa6e3cddb865c058da76756b", + "sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3", + "sha256:57b2533356cb2d8fac1555815929f7f5f14d68ac77b085d2326b571310f34f6e", + "sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc", + "sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04", + "sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6", + "sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359", + "sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596", + "sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b", + "sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd", + "sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95", + "sha256:a6a5cb8809091ec9ac03edde9304b3ad82ad4466333432b16d78ef40e0cce0d5", + "sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e", + "sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6", + "sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca", + "sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31", + "sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1", + "sha256:ca1bd81f40adc59011f58159e4aa6445fc585a32bb8ac9badf7a2c1aa23822f2", + "sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085", + "sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801", + "sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4", + "sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184", + "sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917", + "sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f", + "sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb" + ], + "version": "==1.11.5" + }, + "cryptography": { + "hashes": [ + "sha256:05a6052c6a9f17ff78ba78f8e6eb1d777d25db3b763343a1ae89a7a8670386dd", + "sha256:0eb83a24c650a36f68e31a6d0a70f7ad9c358fa2506dc7b683398b92e354a038", + "sha256:0ff4a3d6ea86aa0c9e06e92a9f986de7ee8231f36c4da1b31c61a7e692ef3378", + "sha256:1699f3e916981df32afdd014fb3164db28cdb61c757029f502cb0a8c29b2fdb3", + "sha256:1b1f136d74f411f587b07c076149c4436a169dc19532e587460d9ced24adcc13", + "sha256:21e63dd20f5e5455e8b34179ac43d95b3fb1ffa54d071fd2ed5d67da82cfe6dc", + "sha256:2454ada8209bbde97065453a6ca488884bbb263e623d35ba183821317a58b46f", + "sha256:3cdc5f7ca057b2214ce4569e01b0f368b3de9d8ee01887557755ccd1c15d9427", + "sha256:418e7a5ec02a7056d3a4f0c0e7ea81df374205f25f4720bb0e84189aa5fd2515", + "sha256:471a097076a7c4ab85561d7fa9a1239bd2ae1f9fd0047520f13d8b340bf3210b", + "sha256:5ecaf9e7db3ca582c6de6229525d35db8a4e59dc3e8a40a331674ed90e658cbf", + "sha256:63b064a074f8dc61be81449796e2c3f4e308b6eba04a241a5c9f2d05e882c681", + "sha256:6afe324dfe6074822ccd56d80420df750e19ac30a4e56c925746c735cf22ae8b", + "sha256:70596e90398574b77929cd87e1ac6e43edd0e29ba01e1365fed9c26bde295aa5", + "sha256:70c2b04e905d3f72e2ba12c58a590817128dfca08949173faa19a42c824efa0b", + "sha256:8908f1db90be48b060888e9c96a0dee9d842765ce9594ff6a23da61086116bb6", + "sha256:af12dfc9874ac27ebe57fc28c8df0e8afa11f2a1025566476b0d50cdb8884f70", + "sha256:b4fc04326b2d259ddd59ed8ea20405d2e695486ab4c5e1e49b025c484845206e", + "sha256:da5b5dda4aa0d5e2b758cc8dfc67f8d4212e88ea9caad5f61ba132f948bab859" + ], + "index": "pypi", + "version": "==2.4.2" + }, + "enum34": { + "hashes": [ + "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", + "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", + "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", + "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" + ], + "markers": "python_version < '3'", + "version": "==1.1.6" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "ipaddress": { + "hashes": [ + "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", + "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" + ], + "markers": "python_version < '3'", + "version": "==1.0.22" + }, + "pycparser": { + "hashes": [ + "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" + ], + "version": "==2.19" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "smime": { + "editable": true, + "extras": [ + "test" + ], + "path": "." + } + } +} diff --git a/setup.py b/setup.py index 40ecc5f..ed56747 100755 --- a/setup.py +++ b/setup.py @@ -35,5 +35,5 @@ packages=find_packages(exclude=['smime/test', 'smime/crypto/testdata', 'smime/crypto/tools', '*_test.py']), platforms=["all"], - install_requires=['cryptography', 'asn1crypto'], + install_requires=['cryptography', 'asn1crypto', 'six'], ) diff --git a/smime/__init__.py b/smime/__init__.py index 63c179b..840e094 100644 --- a/smime/__init__.py +++ b/smime/__init__.py @@ -6,4 +6,3 @@ __all__ = [__author__, __license__, __version__] -from .encrypt import encrypt diff --git a/smime/api.py b/smime/api.py new file mode 100644 index 0000000..61ed3fb --- /dev/null +++ b/smime/api.py @@ -0,0 +1,2 @@ +""" """ +from .encrypt import encrypt \ No newline at end of file diff --git a/smime/encrypt.py b/smime/encrypt.py index f85470f..d89f83e 100644 --- a/smime/encrypt.py +++ b/smime/encrypt.py @@ -1,8 +1,5 @@ -# Refer to RFC3565 -# coding: utf-8 - -from __future__ import unicode_literals - +# _*_ coding: utf-8 _*_ +"""Refer to RFC3565""" from base64 import b64encode from email import message_from_string from email.mime.text import MIMEText @@ -12,7 +9,12 @@ from .print_util import wrap_lines from asn1crypto import cms -from email.message import EmailMessage +import six + +try: + from email.message import EmailMessage +except ImportError: + from email.message import Message as EmailMessage def __iterate_recipient_infos(certs, session_key): @@ -39,7 +41,7 @@ def encrypt(message, certs, algorithm='aes256_cbc'): raise ValueError('Unknown block algorithm') # Get the message content. This could be a string, or a message object - passed_as_str = isinstance(message, str) + passed_as_str = isinstance(message, six.string_types) if passed_as_str: msg = message_from_string(message) else: @@ -47,6 +49,7 @@ def encrypt(message, certs, algorithm='aes256_cbc'): # Extract the message payload without conversion, & the outermost MIME header / Content headers. This allows # the MIME content to be rendered for any outermost MIME type incl. multipart pl = EmailMessage() + for i in msg.items(): hname = i[0].lower() if hname == 'mime-version' or hname.startswith('content-'): @@ -65,11 +68,11 @@ def encrypt(message, certs, algorithm='aes256_cbc'): # Build the enveloped data and encode in base64 enveloped_data = cms.ContentInfo({ - 'content_type': 'enveloped_data', - 'content': { - 'version': 'v0', - 'recipient_infos': recipient_infos, - 'encrypted_content_info': encrypted_content_info + u'content_type': u'enveloped_data', + u'content': { + u'version': u'v0', + u'recipient_infos': recipient_infos, + u'encrypted_content_info': encrypted_content_info } }) encoded_content = '\n'.join(wrap_lines(b64encode(enveloped_data.dump()), 64)) @@ -97,4 +100,4 @@ def encrypt(message, certs, algorithm='aes256_cbc'): if passed_as_str: return result_msg.as_string() else: - return result_msg \ No newline at end of file + return result_msg diff --git a/smime/encrypt_test.py b/smime/encrypt_test.py index eecab06..b98ada7 100644 --- a/smime/encrypt_test.py +++ b/smime/encrypt_test.py @@ -1,15 +1,12 @@ #!/usr/bin/env python -# coding=utf-8 - -from __future__ import unicode_literals - +# _*_ coding: utf-8 _*_ import os import unittest from subprocess import Popen, PIPE from tempfile import mkstemp from smime.test import test_config -from smime import encrypt +from smime.api import encrypt from email import message_from_string @@ -46,7 +43,7 @@ def assertMessageToCarlWith(self, algorithm): 'Now you see me.' ] with open(self.get_file(self._CARL_PUBLIC_CERTIFICATE)) as cert: - result = encrypt('\n'.join(message), cert.read(), algorithm=algorithm) + result = encrypt(u'\n'.join(message), cert.read(), algorithm=algorithm) fd, tmp_file = mkstemp() os.write(fd, result) @@ -61,13 +58,13 @@ def assertMessageToCarlWith(self, algorithm): self.assertEquals('Now you see me.', payload[len(payload)-1]) def test_message_to_carl_aes256_cbc(self): - self.assertMessageToCarlWith('aes256_cbc') + self.assertMessageToCarlWith(u'aes256_cbc') def test_message_to_carl_aes192_cbc(self): - self.assertMessageToCarlWith('aes192_cbc') + self.assertMessageToCarlWith(u'aes192_cbc') def test_message_to_carl_aes128_cbc(self): - self.assertMessageToCarlWith('aes128_cbc') + self.assertMessageToCarlWith(u'aes128_cbc') if __name__ == "__main__": diff --git a/smime/print_util_test.py b/smime/print_util_test.py index f5b3608..00dc39b 100755 --- a/smime/print_util_test.py +++ b/smime/print_util_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python - import unittest -from smime.crypto.asn1 import print_util +from smime import print_util + class PrintUtilTest(unittest.TestCase): def test_bits_to_hex(self): From 4b69705597c6978381d0969877b28458b2be27c8 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 09:52:12 +0100 Subject: [PATCH 02/12] refactor: now all existing headers are kept intact, except To,From,Subject,Bcc,Cc those are included into smime message --- smime/encrypt.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/smime/encrypt.py b/smime/encrypt.py index d89f83e..b6b86d5 100644 --- a/smime/encrypt.py +++ b/smime/encrypt.py @@ -1,6 +1,7 @@ # _*_ coding: utf-8 _*_ """Refer to RFC3565""" from base64 import b64encode +from copy import deepcopy from email import message_from_string from email.mime.text import MIMEText @@ -11,11 +12,6 @@ from asn1crypto import cms import six -try: - from email.message import EmailMessage -except ImportError: - from email.message import Message as EmailMessage - def __iterate_recipient_infos(certs, session_key): if isinstance(certs, (tuple, list)): @@ -42,22 +38,24 @@ def encrypt(message, certs, algorithm='aes256_cbc'): # Get the message content. This could be a string, or a message object passed_as_str = isinstance(message, six.string_types) + if passed_as_str: - msg = message_from_string(message) - else: - msg = message + message = message_from_string(message) # Extract the message payload without conversion, & the outermost MIME header / Content headers. This allows # the MIME content to be rendered for any outermost MIME type incl. multipart - pl = EmailMessage() + copied_msg = deepcopy(message) - for i in msg.items(): - hname = i[0].lower() - if hname == 'mime-version' or hname.startswith('content-'): - pl.add_header(i[0], i[1]) - pl._payload = msg._payload - content = pl.as_string() + headers = {} + for hdr_name in ('Subject', 'To', 'BCC', 'CC', 'From'): + values = copied_msg.get_all(hdr_name) + if values: + del copied_msg[hdr_name] + headers[hdr_name] = values + + content = copied_msg.as_string() recipient_infos = [] + for recipient_info in __iterate_recipient_infos(certs, block_cipher.session_key): if recipient_info == None: raise ValueError('Unknown public-key algorithm') @@ -86,8 +84,8 @@ def encrypt(message, certs, algorithm='aes256_cbc'): ('Content-Disposition', 'attachment; filename=smime.p7m') ) - for name, value in list(msg.items()): - if name in [x for x, _ in overrides]: + for name, value in list(copied_msg.items()): + if name in [x for x, _ in overrides]: continue result_msg.add_header(name, value) @@ -96,6 +94,11 @@ def encrypt(message, certs, algorithm='aes256_cbc'): del result_msg[name] result_msg[name] = value + # adds header + for hrd, values in six.iteritems(headers): + for val in values: + result_msg.add_header(hrd, val) + # return the same type as was passed in if passed_as_str: return result_msg.as_string() From 8581bd9a1217a4bbf81468f1761f827cdd9bd70c Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 10:12:36 +0100 Subject: [PATCH 03/12] flake8 cleanup --- smime/api.py | 2 +- smime/block.py | 5 ++--- smime/cert.py | 2 +- smime/encrypt.py | 8 ++++---- smime/encrypt_test.py | 7 +++---- smime/print_util_test.py | 1 + smime/pubkey.py | 3 +-- smime/test/test_config.py | 2 +- smime/tools/cert_util.py | 6 +++--- smime/tools/cms_util.py | 5 ++--- 10 files changed, 19 insertions(+), 22 deletions(-) diff --git a/smime/api.py b/smime/api.py index 61ed3fb..5ea7d19 100644 --- a/smime/api.py +++ b/smime/api.py @@ -1,2 +1,2 @@ """ """ -from .encrypt import encrypt \ No newline at end of file +from .encrypt import encrypt diff --git a/smime/block.py b/smime/block.py index fa1d3b2..e3db19f 100644 --- a/smime/block.py +++ b/smime/block.py @@ -3,11 +3,10 @@ from __future__ import unicode_literals import os +from abc import ABCMeta, abstractmethod -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend - -from abc import ABCMeta, abstractmethod +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes class BlockCipher(): diff --git a/smime/cert.py b/smime/cert.py index d9f1c1f..ee8c055 100644 --- a/smime/cert.py +++ b/smime/cert.py @@ -6,7 +6,7 @@ import hashlib -from asn1crypto import x509, cms, pem +from asn1crypto import cms, pem, x509 from .pubkey import RSAPublicKeyCipher diff --git a/smime/encrypt.py b/smime/encrypt.py index b6b86d5..1165180 100644 --- a/smime/encrypt.py +++ b/smime/encrypt.py @@ -5,13 +5,13 @@ from email import message_from_string from email.mime.text import MIMEText -from .cert import certs_from_pem +import six +from asn1crypto import cms + from .block import get_cipher +from .cert import certs_from_pem from .print_util import wrap_lines -from asn1crypto import cms -import six - def __iterate_recipient_infos(certs, session_key): if isinstance(certs, (tuple, list)): diff --git a/smime/encrypt_test.py b/smime/encrypt_test.py index b98ada7..4493984 100644 --- a/smime/encrypt_test.py +++ b/smime/encrypt_test.py @@ -2,13 +2,12 @@ # _*_ coding: utf-8 _*_ import os import unittest -from subprocess import Popen, PIPE +from email import message_from_string +from subprocess import PIPE, Popen from tempfile import mkstemp -from smime.test import test_config from smime.api import encrypt - -from email import message_from_string +from smime.test import test_config class EncryptTest(unittest.TestCase): diff --git a/smime/print_util_test.py b/smime/print_util_test.py index 00dc39b..00f2dbd 100755 --- a/smime/print_util_test.py +++ b/smime/print_util_test.py @@ -1,5 +1,6 @@ #!/usr/bin/env python import unittest + from smime import print_util diff --git a/smime/pubkey.py b/smime/pubkey.py index a84ad1c..8abd3b3 100644 --- a/smime/pubkey.py +++ b/smime/pubkey.py @@ -3,7 +3,7 @@ from abc import ABCMeta, abstractmethod from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives.asymmetric import padding, rsa class PublicKeyCipher(object): @@ -37,4 +37,3 @@ def encrypt(self, session_key): def parameters(self): # AlgorithmIdentifier parameters is always NULL return None - diff --git a/smime/test/test_config.py b/smime/test/test_config.py index 1d61b04..f261412 100644 --- a/smime/test/test_config.py +++ b/smime/test/test_config.py @@ -5,4 +5,4 @@ CRYPTO_TEST_DATA_DIR = "smime/testdata/" def get_test_file_path(filename): - return os.path.join(os.curdir, CRYPTO_TEST_DATA_DIR, filename) \ No newline at end of file + return os.path.join(os.curdir, CRYPTO_TEST_DATA_DIR, filename) diff --git a/smime/tools/cert_util.py b/smime/tools/cert_util.py index 46c1995..ad8ae2a 100644 --- a/smime/tools/cert_util.py +++ b/smime/tools/cert_util.py @@ -27,10 +27,10 @@ - print the SHA-256 fingerprint """ -import sys -from smime import cert -from smime import print_util import argparse +import sys + +from smime import cert, print_util def print_cert(args, certificate): diff --git a/smime/tools/cms_util.py b/smime/tools/cms_util.py index 6029762..5ee1308 100755 --- a/smime/tools/cms_util.py +++ b/smime/tools/cms_util.py @@ -18,10 +18,11 @@ cms_util.py --debug message.pem - print full ASN.1 structure """ -import sys import argparse +import sys from base64 import b64decode from traceback import print_exc + from smime.crypto import error from smime.crypto.asn1 import cms @@ -94,5 +95,3 @@ def main(): if __name__ == "__main__": main() - - From cf0990f0bbc8e0ecc3b6a21ec45105f732a00594 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 11:56:00 +0100 Subject: [PATCH 04/12] * full cleanup flake8, isort * say hello to pytest implementation * travis file added * manifest and Changes rst file added --- .gitignore | 64 ++++++++++++- .travis.yml | 30 ++++++ CHANGES.rst | 8 ++ MANIFEST.in | 15 +++ Makefile | 32 +++++++ Pipfile.lock | 166 ++++++++++++++++++++++++++++++++- setup.cfg | 29 ++++++ setup.py | 8 +- smime/__init__.py | 1 - smime/api.py | 2 +- smime/block.py | 30 +++--- smime/cert.py | 59 ++++++------ smime/encrypt.py | 43 +++++---- smime/encrypt_test.py | 42 +++++---- smime/print_util.py | 12 +-- smime/print_util_test.py | 15 +-- smime/pubkey.py | 12 ++- smime/test/test_config.py | 1 + smime/tests/__init__.py | 0 smime/tests/conftest.py | 1 + smime/tests/fixtures.py | 18 ++++ smime/tests/test_encrypt.py | 73 +++++++++++++++ smime/tests/test_print_util.py | 51 ++++++++++ smime/tools/cert_util.py | 3 +- 24 files changed, 613 insertions(+), 102 deletions(-) create mode 100644 .travis.yml create mode 100644 CHANGES.rst create mode 100644 MANIFEST.in create mode 100644 Makefile create mode 100644 setup.cfg create mode 100644 smime/tests/__init__.py create mode 100644 smime/tests/conftest.py create mode 100644 smime/tests/fixtures.py create mode 100644 smime/tests/test_encrypt.py create mode 100755 smime/tests/test_print_util.py diff --git a/.gitignore b/.gitignore index 640b090..da551a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,68 @@ .idea .*.swp -*.pyc build/ smime.egg-info/ dist/ +.pytest_cache/ +.coverage + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# editor +.idea +.vscode +*.sublime-* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..78a3053 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +# Config file for automatic testing at travis-ci.org +dist: xenial +language: python +sudo: required +matrix: + include: + - name: Python 2.7 + python: 2.7 + - name: Python 3.4 + python: 3.4 + - name: Python 3.5 + python: 3.5 + - name: Python 3.6 + python: 3.6 + - name: Python 3.7 + python: 3.7 + +cache: + directories: + - eggs +install: + - pip install -U pipenv + - pipenv install --dev + - sleep 5 +script: + - make lint + - make clean + - pytest -s --cov=smime/ -s --tb=native -v --cov-report term-missing --cov-append smime/ +after_success: + - codecov diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 index 0000000..b2373fd --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,8 @@ +======= +CHANGES +======= + +0.0.5 (unreleased) +------------------ + +- Nothing changed yet. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..d6626a0 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,15 @@ +graft src/guillotina_fhirfield +prune docs +prune .github +include AUTHORS.rst +include CONTRIBUTING.rst +include CHANGES.rst +include LICENSE +include README.rst + +recursive-include tests * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] + +exclude Makefile .editorconfig Pipfile* tox.ini .coveragerc .readthedocs.yml docs-requirements.txt + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..77c628d --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts + +clean-build: ## remove build artifacts + rm -fr build/ + rm -fr dist/ + rm -fr .eggs/ + find . -name '*.egg-info' -exec rm -fr {} + + find . -name '*.egg' -exec rm -f {} + + +clean-pyc: ## remove Python file artifacts + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + +clean-test: ## remove test and coverage artifacts + rm -fr .tox/ + rm -f .coverage + rm -fr htmlcov/ + rm -fr .pytest_cache + +lint: ## check style with flake8 + flake8 smime/ + +isort: ## run isort recursively + isort smime/ -rc + +test: ## run tests quickly with the default Python + py.test smime/tests + +install: clean ## install the package to the active Python's site-packages + python setup.py install diff --git a/Pipfile.lock b/Pipfile.lock index 2a835ec..399e54a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -144,7 +144,7 @@ "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" ], - "markers": "python_version < '3'", + "markers": "python_version < '3.4'", "version": "==1.1.6" }, "flake8": { @@ -332,6 +332,20 @@ "index": "pypi", "version": "==0.24.0" }, + "atomicwrites": { + "hashes": [ + "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", + "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" + ], + "version": "==1.2.1" + }, + "attrs": { + "hashes": [ + "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", + "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" + ], + "version": "==18.2.0" + }, "cffi": { "hashes": [ "sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743", @@ -369,6 +383,49 @@ ], "version": "==1.11.5" }, + "configparser": { + "hashes": [ + "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a" + ], + "markers": "python_version < '3.2'", + "version": "==3.5.0" + }, + "coverage": { + "hashes": [ + "sha256:09e47c529ff77bf042ecfe858fb55c3e3eb97aac2c87f0349ab5a7efd6b3939f", + "sha256:0a1f9b0eb3aa15c990c328535655847b3420231af299386cfe5efc98f9c250fe", + "sha256:0cc941b37b8c2ececfed341444a456912e740ecf515d560de58b9a76562d966d", + "sha256:10e8af18d1315de936d67775d3a814cc81d0747a1a0312d84e27ae5610e313b0", + "sha256:1b4276550b86caa60606bd3572b52769860a81a70754a54acc8ba789ce74d607", + "sha256:1e8a2627c48266c7b813975335cfdea58c706fe36f607c97d9392e61502dc79d", + "sha256:2b224052bfd801beb7478b03e8a66f3f25ea56ea488922e98903914ac9ac930b", + "sha256:447c450a093766744ab53bf1e7063ec82866f27bcb4f4c907da25ad293bba7e3", + "sha256:46101fc20c6f6568561cdd15a54018bb42980954b79aa46da8ae6f008066a30e", + "sha256:4710dc676bb4b779c4361b54eb308bc84d64a2fa3d78e5f7228921eccce5d815", + "sha256:510986f9a280cd05189b42eee2b69fecdf5bf9651d4cd315ea21d24a964a3c36", + "sha256:5535dda5739257effef56e49a1c51c71f1d37a6e5607bb25a5eee507c59580d1", + "sha256:5a7524042014642b39b1fcae85fb37556c200e64ec90824ae9ecf7b667ccfc14", + "sha256:5f55028169ef85e1fa8e4b8b1b91c0b3b0fa3297c4fb22990d46ff01d22c2d6c", + "sha256:6694d5573e7790a0e8d3d177d7a416ca5f5c150742ee703f3c18df76260de794", + "sha256:6831e1ac20ac52634da606b658b0b2712d26984999c9d93f0c6e59fe62ca741b", + "sha256:77f0d9fa5e10d03aa4528436e33423bfa3718b86c646615f04616294c935f840", + "sha256:828ad813c7cdc2e71dcf141912c685bfe4b548c0e6d9540db6418b807c345ddd", + "sha256:85a06c61598b14b015d4df233d249cd5abfa61084ef5b9f64a48e997fd829a82", + "sha256:8cb4febad0f0b26c6f62e1628f2053954ad2c555d67660f28dfb1b0496711952", + "sha256:a5c58664b23b248b16b96253880b2868fb34358911400a7ba39d7f6399935389", + "sha256:aaa0f296e503cda4bc07566f592cd7a28779d433f3a23c48082af425d6d5a78f", + "sha256:ab235d9fe64833f12d1334d29b558aacedfbca2356dfb9691f2d0d38a8a7bfb4", + "sha256:b3b0c8f660fae65eac74fbf003f3103769b90012ae7a460863010539bb7a80da", + "sha256:bab8e6d510d2ea0f1d14f12642e3f35cefa47a9b2e4c7cea1852b52bc9c49647", + "sha256:c45297bbdbc8bb79b02cf41417d63352b70bcb76f1bbb1ee7d47b3e89e42f95d", + "sha256:d19bca47c8a01b92640c614a9147b081a1974f69168ecd494687c827109e8f42", + "sha256:d64b4340a0c488a9e79b66ec9f9d77d02b99b772c8b8afd46c1294c1d39ca478", + "sha256:da969da069a82bbb5300b59161d8d7c8d423bc4ccd3b410a9b4d8932aeefc14b", + "sha256:ed02c7539705696ecb7dc9d476d861f3904a8d2b7e894bd418994920935d36bb", + "sha256:ee5b8abc35b549012e03a7b1e86c09491457dba6c94112a2482b18589cc2bdb9" + ], + "version": "==4.5.2" + }, "cryptography": { "hashes": [ "sha256:05a6052c6a9f17ff78ba78f8e6eb1d777d25db3b763343a1ae89a7a8670386dd", @@ -401,9 +458,25 @@ "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" ], - "markers": "python_version < '3'", + "markers": "python_version < '3.4'", "version": "==1.1.6" }, + "flake8": { + "hashes": [ + "sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670", + "sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2" + ], + "index": "pypi", + "version": "==3.6.0" + }, + "funcsigs": { + "hashes": [ + "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", + "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50" + ], + "markers": "python_version < '3.0'", + "version": "==1.0.2" + }, "idna": { "hashes": [ "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", @@ -419,12 +492,101 @@ "markers": "python_version < '3'", "version": "==1.0.22" }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "more-itertools": { + "hashes": [ + "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4", + "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc", + "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9" + ], + "version": "==5.0.0" + }, + "pathlib2": { + "hashes": [ + "sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742", + "sha256:5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7" + ], + "markers": "python_version < '3.6'", + "version": "==2.3.3" + }, + "pluggy": { + "hashes": [ + "sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", + "sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f" + ], + "version": "==0.8.0" + }, + "py": { + "hashes": [ + "sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", + "sha256:e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6" + ], + "version": "==1.7.0" + }, + "pycodestyle": { + "hashes": [ + "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", + "sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" + ], + "version": "==2.4.0" + }, "pycparser": { "hashes": [ "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" ], "version": "==2.19" }, + "pyflakes": { + "hashes": [ + "sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49", + "sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae" + ], + "version": "==2.0.0" + }, + "pytest": { + "hashes": [ + "sha256:f689bf2fc18c4585403348dd56f47d87780bf217c53ed9ae7a3e2d7faa45f8e9", + "sha256:f812ea39a0153566be53d88f8de94839db1e8a05352ed8a49525d7d7f37861e9" + ], + "version": "==4.0.2" + }, + "pytest-cov": { + "hashes": [ + "sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7", + "sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762" + ], + "version": "==2.6.0" + }, + "pytest-flake8": { + "hashes": [ + "sha256:4f30f5be3efb89755f38f11bdb2a5e22d19a6f5faa73428f703a3292a9572cd3", + "sha256:c740ad6aa19e3958947d2118f70bed218caf1d2097039fb7318573a2a72f89a1" + ], + "version": "==1.0.2" + }, + "scandir": { + "hashes": [ + "sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6", + "sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e", + "sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6", + "sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e", + "sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064", + "sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792", + "sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a", + "sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383", + "sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b", + "sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8", + "sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd" + ], + "markers": "python_version < '3.5'", + "version": "==1.9.0" + }, "six": { "hashes": [ "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..13ce799 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,29 @@ +[tool:pytest] +flake8-max-line-length = 120 + +[bdist_wheel] +universal = 1 + +[flake8] +exclude = + docs + smime/tools/ + smime/testdata/ + smime/test/ + +max_line_length = 120 +no-accept-encodings = True + +[aliases] +# Define setup.py command aliases here +test = pytest + +[isort] +lines_after_imports=2 +force_single_line=true +line_length=120 +not_skip=__init__.py + +[zest.releaser] +create-wheel = yes +register = no \ No newline at end of file diff --git a/setup.py b/setup.py index ed56747..5d1dd2d 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ # Get the long description from the README file with open(path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() - +test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( name='smime', version=__import__('smime').__version__, @@ -36,4 +36,10 @@ 'smime/crypto/tools', '*_test.py']), platforms=["all"], install_requires=['cryptography', 'asn1crypto', 'six'], + setup_requires=['pytest-runner'], + tests_require=test_requires, + test_suite='tests', + extras_require={ + 'test': test_requires + } ) diff --git a/smime/__init__.py b/smime/__init__.py index 840e094..639006e 100644 --- a/smime/__init__.py +++ b/smime/__init__.py @@ -5,4 +5,3 @@ __version__ = '0.0.4' __all__ = [__author__, __license__, __version__] - diff --git a/smime/api.py b/smime/api.py index 5ea7d19..3dbb7bf 100644 --- a/smime/api.py +++ b/smime/api.py @@ -1,2 +1,2 @@ """ """ -from .encrypt import encrypt +from .encrypt import encrypt # noqa: F401 diff --git a/smime/block.py b/smime/block.py index e3db19f..f9e10b9 100644 --- a/smime/block.py +++ b/smime/block.py @@ -3,13 +3,16 @@ from __future__ import unicode_literals import os -from abc import ABCMeta, abstractmethod +from abc import ABCMeta +from abc import abstractmethod from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers import algorithms +from cryptography.hazmat.primitives.ciphers import modes -class BlockCipher(): +class BlockCipher: __metaclass__ = ABCMeta @abstractmethod @@ -47,14 +50,17 @@ def session_key(self): def encrypt(self, data): padded_data = self._pad(data, self.block_size) - encrypted_content = self._encryptor.update(padded_data.encode('utf-8')) + self._encryptor.finalize() + encrypted_content = ( + self._encryptor.update(padded_data.encode("utf-8")) + + self._encryptor.finalize() + ) return { - 'content_type': 'data', - 'content_encryption_algorithm': { - 'algorithm': self.algorithm, - 'parameters': self._iv + "content_type": "data", + "content_encryption_algorithm": { + "algorithm": self.algorithm, + "parameters": self._iv, }, - 'encrypted_content': encrypted_content + "encrypted_content": encrypted_content, } @staticmethod @@ -69,9 +75,9 @@ def parameters(self): def get_cipher(algorithm): algorithms = { - 'aes128_cbc': (AES, (modes.CBC, 16)), - 'aes192_cbc': (AES, (modes.CBC, 24)), - 'aes256_cbc': (AES, (modes.CBC, 32)), + "aes128_cbc": (AES, (modes.CBC, 16)), + "aes192_cbc": (AES, (modes.CBC, 24)), + "aes256_cbc": (AES, (modes.CBC, 32)), } if algorithm in algorithms: cipher, parameters = algorithms[algorithm] diff --git a/smime/cert.py b/smime/cert.py index ee8c055..d4cf469 100644 --- a/smime/cert.py +++ b/smime/cert.py @@ -6,19 +6,23 @@ import hashlib -from asn1crypto import cms, pem, x509 +from asn1crypto import cms +from asn1crypto import pem +from asn1crypto import x509 from .pubkey import RSAPublicKeyCipher class CertificateError(Exception): """Certificate has errors.""" + pass class Certificate(object): """X509 certificates.""" - PEM_MARKERS = ('CERTIFICATE',) + + PEM_MARKERS = ("CERTIFICATE",) def __init__(self, der_string): """Initialize from a DER string. @@ -86,7 +90,7 @@ def from_pem_file(cls, pem_file): Returns: a Certificate object """ - with open(pem_file, 'rb') as pem_cert_file: + with open(pem_file, "rb") as pem_cert_file: return cls.from_pem(pem_cert_file.read()) @classmethod @@ -99,7 +103,7 @@ def from_der_file(cls, der_file): Returns: a Certificate object. """ - with open(der_file, 'rb') as der_cert_file: + with open(der_file, "rb") as der_cert_file: return cls.from_der(der_cert_file.read()) def to_der(self): @@ -125,8 +129,10 @@ def self_signed(self): Returns: True or False. """ - return (self._cert['tbs_certificate']['issuer'] == - self._cert['tbs_certificate']['subject']) + return ( + self._cert["tbs_certificate"]["issuer"] + == self._cert["tbs_certificate"]["subject"] + ) def fingerprint(self, hashfunc="sha1"): """Get the certificate fingerprint. @@ -151,8 +157,7 @@ def key_hash(self, hashfunc="sha1"): a (binary) hash digest of the public key. """ h = hashlib.new(hashfunc) - h.update( - self._cert['tbs_certificate']['subject_public_key_info'].dump()) + h.update(self._cert["tbs_certificate"]["subject_public_key_info"].dump()) return h.digest() def _get_public_key_cipher(self): @@ -160,9 +165,7 @@ def _get_public_key_cipher(self): :return: The PublicKey object for this certificate """ - algorithms = { - RSAPublicKeyCipher.algo: RSAPublicKeyCipher - } + algorithms = {RSAPublicKeyCipher.algo: RSAPublicKeyCipher} public_key_info = self._cert.public_key algorithm = public_key_info.algorithm if algorithm not in algorithms: @@ -172,28 +175,28 @@ def _get_public_key_cipher(self): def recipient_info(self, session_key): cipher = self._get_public_key_cipher() - if cipher == None: + if cipher is None: return None encrypted_key = cipher.encrypt(session_key) - tbs_cert = self._cert['tbs_certificate'] + tbs_cert = self._cert["tbs_certificate"] # TODO: use subject_key_identifier when available return cms.RecipientInfo( - name = 'ktri', - value = { - 'version': u'v0', - 'rid': cms.RecipientIdentifier( - name = 'issuer_and_serial_number', - value = { - 'issuer': tbs_cert['issuer'], - 'serial_number': tbs_cert['serial_number'] - } + name="ktri", + value={ + "version": "v0", + "rid": cms.RecipientIdentifier( + name="issuer_and_serial_number", + value={ + "issuer": tbs_cert["issuer"], + "serial_number": tbs_cert["serial_number"], + }, ), - 'key_encryption_algorithm': { - 'algorithm': cipher.algo, - 'parameters': cipher.parameters + "key_encryption_algorithm": { + "algorithm": cipher.algo, + "parameters": cipher.parameters, }, - 'encrypted_key': encrypted_key - } + "encrypted_key": encrypted_key, + }, ) @@ -219,5 +222,5 @@ def certs_from_pem_file(pem_file): Yields: Certificate objects. """ - with open(pem_file, 'rb') as certs_pem_file: + with open(pem_file, "rb") as certs_pem_file: return certs_from_pem(certs_pem_file.read()) diff --git a/smime/encrypt.py b/smime/encrypt.py index 1165180..5b2e2a0 100644 --- a/smime/encrypt.py +++ b/smime/encrypt.py @@ -25,7 +25,7 @@ def __iterate_recipient_infos(certs, session_key): yield recipient_info -def encrypt(message, certs, algorithm='aes256_cbc'): +def encrypt(message, certs, algorithm="aes256_cbc"): """ Takes the contents of the message parameter, formatted as in RFC 2822 (type str or message), and encrypts them, so that they can only be read by the intended recipient specified by pubkey. @@ -33,8 +33,8 @@ def encrypt(message, certs, algorithm='aes256_cbc'): """ # Get the chosen block cipher block_cipher = get_cipher(algorithm) - if block_cipher == None: - raise ValueError('Unknown block algorithm') + if block_cipher is None: + raise ValueError("Unknown block algorithm") # Get the message content. This could be a string, or a message object passed_as_str = isinstance(message, six.string_types) @@ -46,8 +46,8 @@ def encrypt(message, certs, algorithm='aes256_cbc'): copied_msg = deepcopy(message) headers = {} - - for hdr_name in ('Subject', 'To', 'BCC', 'CC', 'From'): + # bellows headers are wiped from cloned and would be added in newly created message instance + for hdr_name in ("Subject", "To", "BCC", "CC", "From"): values = copied_msg.get_all(hdr_name) if values: del copied_msg[hdr_name] @@ -57,31 +57,36 @@ def encrypt(message, certs, algorithm='aes256_cbc'): recipient_infos = [] for recipient_info in __iterate_recipient_infos(certs, block_cipher.session_key): - if recipient_info == None: - raise ValueError('Unknown public-key algorithm') + if recipient_info is None: + raise ValueError("Unknown public-key algorithm") recipient_infos.append(recipient_info) # Encode the content encrypted_content_info = block_cipher.encrypt(content) # Build the enveloped data and encode in base64 - enveloped_data = cms.ContentInfo({ - u'content_type': u'enveloped_data', - u'content': { - u'version': u'v0', - u'recipient_infos': recipient_infos, - u'encrypted_content_info': encrypted_content_info + enveloped_data = cms.ContentInfo( + { + u"content_type": u"enveloped_data", + u"content": { + u"version": u"v0", + u"recipient_infos": recipient_infos, + u"encrypted_content_info": encrypted_content_info, + }, } - }) - encoded_content = '\n'.join(wrap_lines(b64encode(enveloped_data.dump()), 64)) + ) + encoded_content = "\n".join(wrap_lines(b64encode(enveloped_data.dump()), 64)) # Create the resulting message result_msg = MIMEText(encoded_content) overrides = ( - ('MIME-Version', '1.0'), - ('Content-Type', 'application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m'), - ('Content-Transfer-Encoding', 'base64'), - ('Content-Disposition', 'attachment; filename=smime.p7m') + ("MIME-Version", "1.0"), + ( + "Content-Type", + "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m", + ), + ("Content-Transfer-Encoding", "base64"), + ("Content-Disposition", "attachment; filename=smime.p7m"), ) for name, value in list(copied_msg.items()): diff --git a/smime/encrypt_test.py b/smime/encrypt_test.py index 4493984..216f8b0 100644 --- a/smime/encrypt_test.py +++ b/smime/encrypt_test.py @@ -3,7 +3,8 @@ import os import unittest from email import message_from_string -from subprocess import PIPE, Popen +from subprocess import PIPE +from subprocess import Popen from tempfile import mkstemp from smime.api import encrypt @@ -11,8 +12,8 @@ class EncryptTest(unittest.TestCase): - _CARL_PUBLIC_CERTIFICATE = 'CarlRSASelf.pem' - _CARL_PRIVATE_CERTIFICATE = 'CarlPrivRSASign.pem' + _CARL_PUBLIC_CERTIFICATE = "CarlRSASelf.pem" + _CARL_PRIVATE_CERTIFICATE = "CarlPrivRSASign.pem" def get_file(self, filename): return test_config.get_test_file_path(filename) @@ -21,49 +22,52 @@ def get_cmd_output(self, args): child = Popen(args, stdout=PIPE, stderr=PIPE) result = [] while True: - for line in iter(child.stdout.readline, ''): + for line in iter(child.stdout.readline, ""): result.append(line) if child.poll() is not None: break if child.returncode != 0: error = [] - for line in iter(child.stderr.readline, ''): + for line in iter(child.stderr.readline, ""): error.append(line) - self.fail(("Command: %s\n%s" % - (' '.join(args), ''.join(error)))) - return '\n'.join(result) + self.fail(("Command: %s\n%s" % (" ".join(args), "".join(error)))) + return "\n".join(result) def assertMessageToCarlWith(self, algorithm): message = [ 'From: "Alice" ', 'To: "Carl" ', - 'Subject: A message from python', - '', - 'Now you see me.' + "Subject: A message from python", + "", + "Now you see me.", ] with open(self.get_file(self._CARL_PUBLIC_CERTIFICATE)) as cert: - result = encrypt(u'\n'.join(message), cert.read(), algorithm=algorithm) + result = encrypt(u"\n".join(message), cert.read(), algorithm=algorithm) fd, tmp_file = mkstemp() os.write(fd, result) cmd = [ - 'openssl', 'smime', '-decrypt', - '-in', tmp_file, - '-inkey', self.get_file(self._CARL_PRIVATE_CERTIFICATE) + "openssl", + "smime", + "-decrypt", + "-in", + tmp_file, + "-inkey", + self.get_file(self._CARL_PRIVATE_CERTIFICATE), ] cmd_output = self.get_cmd_output(cmd) private_message = message_from_string(cmd_output) payload = private_message.get_payload().splitlines() - self.assertEquals('Now you see me.', payload[len(payload)-1]) + self.assertEquals("Now you see me.", payload[len(payload) - 1]) def test_message_to_carl_aes256_cbc(self): - self.assertMessageToCarlWith(u'aes256_cbc') + self.assertMessageToCarlWith(u"aes256_cbc") def test_message_to_carl_aes192_cbc(self): - self.assertMessageToCarlWith(u'aes192_cbc') + self.assertMessageToCarlWith(u"aes192_cbc") def test_message_to_carl_aes128_cbc(self): - self.assertMessageToCarlWith(u'aes128_cbc') + self.assertMessageToCarlWith(u"aes128_cbc") if __name__ == "__main__": diff --git a/smime/print_util.py b/smime/print_util.py index 01e04dc..b18d7e6 100644 --- a/smime/print_util.py +++ b/smime/print_util.py @@ -14,7 +14,7 @@ def bits_to_hex(bit_array, delimiter=":"): pad_length = 8 - partial_bits if partial_bits else 0 bitstring = "0" * pad_length + "".join(map(str, bit_array)) - byte_array = [int(bitstring[i:i + 8], 2) for i in range(0, len(bitstring), 8)] + byte_array = [int(bitstring[i: i + 8], 2) for i in range(0, len(bitstring), 8)] return delimiter.join(map(lambda x: "%02x" % x, byte_array)) @@ -39,13 +39,13 @@ def int_to_hex(int_value, delimiter=":"): ret = "" pos = 0 # Accommodate for negative integers. - if hex_string[0] == '-': - ret += ' -' + delimiter + if hex_string[0] == "-": + ret += " -" + delimiter hex_string = hex_string[1:] # If the first digit is a half-byte, pad with a 0. remaining_len = len(hex_string) - pos hex_string = hex_string.zfill(remaining_len + remaining_len % 2) - byte_values = [hex_string[i:i + 2] for i in range(pos, len(hex_string), 2)] + byte_values = [hex_string[i: i + 2] for i in range(pos, len(hex_string), 2)] return ret + delimiter.join(byte_values) @@ -60,7 +60,7 @@ def wrap_lines(long_string, wrap): a list of lines of at most |wrap| characters each.""" if not long_string: return [] - long_lines = long_string.decode('utf-8').split('\n') + long_lines = long_string.decode("utf-8").split("\n") if wrap <= 0: return long_lines ret = [] @@ -69,7 +69,7 @@ def wrap_lines(long_string, wrap): # Empty line ret += [line] else: - ret += [line[i:i + wrap] for i in range(0, len(line), wrap)] + ret += [line[i: i + wrap] for i in range(0, len(line), wrap)] return ret diff --git a/smime/print_util_test.py b/smime/print_util_test.py index 00f2dbd..665c8b0 100755 --- a/smime/print_util_test.py +++ b/smime/print_util_test.py @@ -6,7 +6,7 @@ class PrintUtilTest(unittest.TestCase): def test_bits_to_hex(self): - bit_array = [0,1,1,0,1,0,1,1,1,0] + bit_array = [0, 1, 1, 0, 1, 0, 1, 1, 1, 0] self.assertEqual("01:ae", print_util.bits_to_hex(bit_array)) self.assertEqual("01ae", print_util.bits_to_hex(bit_array, delimiter="")) self.assertEqual("", print_util.bits_to_hex("")) @@ -18,7 +18,7 @@ def test_bytes_to_hex(self): self.assertEqual("", print_util.bytes_to_hex("")) def test_int_to_hex(self): - integer = 1234 # 0x4d2 + integer = 1234 # 0x4d2 self.assertEqual("04:d2", print_util.int_to_hex(integer)) self.assertEqual("04d2", print_util.int_to_hex(integer, delimiter="")) negative_integer = -1234 @@ -26,13 +26,15 @@ def test_int_to_hex(self): def test_wrap_lines(self): long_multiline_string = "hello\nworld" - self.assertEqual(["hel", "lo", "wor", "ld"], - print_util.wrap_lines(long_multiline_string, 3)) + self.assertEqual( + ["hel", "lo", "wor", "ld"], print_util.wrap_lines(long_multiline_string, 3) + ) def test_wrap_lines_no_wrap(self): long_multiline_string = "hello\nworld" - self.assertEqual(["hello", "world"], - print_util.wrap_lines(long_multiline_string, 0)) + self.assertEqual( + ["hello", "world"], print_util.wrap_lines(long_multiline_string, 0) + ) def test_append_lines_appends(self): buf = ["hello"] @@ -48,5 +50,6 @@ def test_append_lines_honours_wrap(self): print_util.append_lines(lines, 10, buf) self.assertEqual(["hello", "beautiful", "world"], buf) + if __name__ == "__main__": unittest.main() diff --git a/smime/pubkey.py b/smime/pubkey.py index 8abd3b3..052eaa5 100644 --- a/smime/pubkey.py +++ b/smime/pubkey.py @@ -1,9 +1,11 @@ from __future__ import unicode_literals -from abc import ABCMeta, abstractmethod +from abc import ABCMeta +from abc import abstractmethod from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import padding, rsa +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.asymmetric import rsa class PublicKeyCipher(object): @@ -21,11 +23,11 @@ def parameters(self): class RSAPublicKeyCipher(PublicKeyCipher): - algo = 'rsa' + algo = "rsa" def __init__(self, public_key_info): - rsaparams = public_key_info['public_key'].native - key = rsa.RSAPublicNumbers(rsaparams['public_exponent'], rsaparams['modulus']) + rsaparams = public_key_info["public_key"].native + key = rsa.RSAPublicNumbers(rsaparams["public_exponent"], rsaparams["modulus"]) backend = default_backend() self._cipher = key.public_key(backend) self._padding = padding.PKCS1v15() diff --git a/smime/test/test_config.py b/smime/test/test_config.py index f261412..61d72df 100644 --- a/smime/test/test_config.py +++ b/smime/test/test_config.py @@ -2,6 +2,7 @@ import os + CRYPTO_TEST_DATA_DIR = "smime/testdata/" def get_test_file_path(filename): diff --git a/smime/tests/__init__.py b/smime/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smime/tests/conftest.py b/smime/tests/conftest.py new file mode 100644 index 0000000..457b022 --- /dev/null +++ b/smime/tests/conftest.py @@ -0,0 +1 @@ +pytest_plugins = ['smime.tests.fixtures'] diff --git a/smime/tests/fixtures.py b/smime/tests/fixtures.py new file mode 100644 index 0000000..6a297ed --- /dev/null +++ b/smime/tests/fixtures.py @@ -0,0 +1,18 @@ +# _*_ coding: utf-8 _*_ +import os + +import pytest + + +BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +@pytest.fixture(scope='module') +def base_settings(): + + settings = dict() + settings['testdata_dir'] = os.path.join(BASE_PATH, 'testdata') + settings['carl_public_certificate'] = os.path.join(settings['testdata_dir'], 'CarlRSASelf.pem') + settings['carl_private_certificate'] = os.path.join(settings['testdata_dir'], 'CarlPrivRSASign.pem') + + yield settings diff --git a/smime/tests/test_encrypt.py b/smime/tests/test_encrypt.py new file mode 100644 index 0000000..5077e69 --- /dev/null +++ b/smime/tests/test_encrypt.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# _*_ coding: utf-8 _*_ +import os +import sys +from email import message_from_string +from subprocess import PIPE +from subprocess import Popen +from tempfile import mkstemp + +from smime.api import encrypt + + +def get_cmd_output(args): + child = Popen(args, stdout=PIPE, stderr=PIPE) + result = [] + while True: + for line in iter(child.stdout.readline, ""): + result.append(line) + if child.poll() is not None: + break + if child.returncode != 0: + error = [] + for line in iter(child.stderr.readline, ""): + error.append(line) + sys.stderr.write("Command: %s\n%s" % (" ".join(args), "".join(error))) + return "\n".join(result) + + +def assert_message_to_carl(settings, algorithm): + message = [ + 'From: "Alice" ', + 'To: "Carl" ', + "Subject: A message from python", + "", + "Now you see me.", + ] + with open(settings['carl_public_certificate']) as cert: + result = encrypt(u"\n".join(message), cert.read(), algorithm=algorithm) + + fd, tmp_file = mkstemp() + os.write(fd, result) + + cmd = [ + "openssl", + "smime", + "-decrypt", + "-in", + tmp_file, + "-inkey", + settings['carl_private_certificate'], + ] + cmd_output = get_cmd_output(cmd) + private_message = message_from_string(cmd_output) + payload = private_message.get_payload().splitlines() + + assert "Now you see me." == payload[len(payload) - 1] + + return 1 + + +def test_message_to_carl_aes256_cbc(base_settings): + settings = base_settings + assert assert_message_to_carl(settings, u"aes256_cbc") == 1 + + +def test_message_to_carl_aes192_cbc(base_settings): + settings = base_settings + assert assert_message_to_carl(settings, u"aes192_cbc") == 1 + + +def test_message_to_carl_aes128_cbc(base_settings): + settings = base_settings + assert assert_message_to_carl(settings, u"aes128_cbc") == 1 diff --git a/smime/tests/test_print_util.py b/smime/tests/test_print_util.py new file mode 100755 index 0000000..e6c9c4f --- /dev/null +++ b/smime/tests/test_print_util.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +from smime import print_util + + +def test_bits_to_hex(): + bit_array = [0, 1, 1, 0, 1, 0, 1, 1, 1, 0] + assert "01:ae" == print_util.bits_to_hex(bit_array) + assert "01ae" == print_util.bits_to_hex(bit_array, delimiter="") + assert "" == print_util.bits_to_hex("") + + +def test_bytes_to_hex(): + byte_array = "\x01\xae" + assert "01:ae" == print_util.bytes_to_hex(byte_array) + assert "01ae" == print_util.bytes_to_hex(byte_array, delimiter="") + assert "" == print_util.bytes_to_hex("") + + +def test_int_to_hex(): + integer = 1234 # 0x4d2 + assert "04:d2" == print_util.int_to_hex(integer) + assert "04d2" == print_util.int_to_hex(integer, delimiter="") + + negative_integer = -1234 + assert " -:04:d2" == print_util.int_to_hex(negative_integer) + + +def test_wrap_lines(): + long_multiline_string = "hello\nworld" + assert ["hel", "lo", "wor", "ld"] == print_util.wrap_lines(long_multiline_string, 3) + + +def test_wrap_lines_no_wrap(): + long_multiline_string = "hello\nworld" + assert ["hello", "world"] == print_util.wrap_lines(long_multiline_string, 0) + + +def test_append_lines_appends(): + buf = ["hello"] + lines = ["beautiful", "world"] + # "hellobeautiful" is more than 10 characters long + print_util.append_lines(lines, 20, buf) + assert ["hellobeautiful", "world"] == buf + + +def test_append_lines_honours_wrap(): + buf = ["hello"] + lines = ["beautiful", "world"] + # "hellobeautiful" is more than 10 characters long + print_util.append_lines(lines, 10, buf) + assert ["hello", "beautiful", "world"] == buf diff --git a/smime/tools/cert_util.py b/smime/tools/cert_util.py index ad8ae2a..90d8f9d 100644 --- a/smime/tools/cert_util.py +++ b/smime/tools/cert_util.py @@ -30,7 +30,8 @@ import argparse import sys -from smime import cert, print_util +from smime import cert +from smime import print_util def print_cert(args, certificate): From 480c8205e0cf21751c802e1939629d2964729cb7 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:24:57 +0100 Subject: [PATCH 05/12] readme updated with proper credit trevis file updated --- .travis.yml | 9 +++++++-- MANIFEST.in | 13 ++++++------- README.rst | 4 ++++ setup.py | 7 +++++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 78a3053..e2cf41f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,19 @@ matrix: include: - name: Python 2.7 python: 2.7 - - name: Python 3.4 - python: 3.4 + env: python_version=2.7 + - name: Python 3.5 python: 3.5 + env: python_version=3.5 + - name: Python 3.6 python: 3.6 + env: python_version=3.6 + - name: Python 3.7 python: 3.7 + env: python_version=3.7 cache: directories: diff --git a/MANIFEST.in b/MANIFEST.in index d6626a0..15d4390 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,15 +1,14 @@ -graft src/guillotina_fhirfield -prune docs -prune .github -include AUTHORS.rst -include CONTRIBUTING.rst +graft smime +include AUTHORS +include CONTRIBUTING.md include CHANGES.rst include LICENSE include README.rst -recursive-include tests * +recursive-exclude test * +recursive-exclude tool * recursive-exclude * __pycache__ recursive-exclude * *.py[co] -exclude Makefile .editorconfig Pipfile* tox.ini .coveragerc .readthedocs.yml docs-requirements.txt +exclude Makefile .editorconfig Pipfile* tox.ini .coveragerc diff --git a/README.rst b/README.rst index 495c01b..2a07a02 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,10 @@ Python S/MIME Toolkit ===================== +.. warning:: + This package is pure fork version of https://github.com/balena/python-smime. All credits go to original Author(s). + Publisher of this fork version (Md Nazrul Islam) doest not reserve any Copyright rights. + This library implements a S/MIME handler. It supports only S/MIME messages encryption using a public RSA key, in AES128-CBC, AES192-CBC or AES256-CBC modes. diff --git a/setup.py b/setup.py index 5d1dd2d..cb32606 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,10 @@ # Get the long description from the README file with open(path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() + +with open(path.join(here, 'CHANGES.rst'), encoding='utf-8') as f: + long_description += '\n\n' + f.read() + test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( name='smime', @@ -27,6 +31,9 @@ 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Libraries', 'Topic :: Communications :: Email', 'Topic :: Security :: Cryptography', From 21c085d8b9215d51e689eadb13b91b4f5746c024 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:42:32 +0100 Subject: [PATCH 06/12] prepare for first release of beta --- README.rst | 3 ++- setup.py | 2 +- smime/__init__.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2a07a02..8133d8e 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,8 @@ Python S/MIME Toolkit ===================== .. warning:: - This package is pure fork version of https://github.com/balena/python-smime. All credits go to original Author(s). + This package is pure fork version from https://github.com/balena/python-smime with immediate release version which contains some necessary refactoring. + All credits go to original Author(s). Publisher of this fork version (Md Nazrul Islam) doest not reserve any Copyright rights. This library implements a S/MIME handler. It supports only S/MIME messages diff --git a/setup.py b/setup.py index cb32606..e3ab77f 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( - name='smime', + name='smime-py23', version=__import__('smime').__version__, description='Python S/MIME Toolkit', long_description=long_description, diff --git a/smime/__init__.py b/smime/__init__.py index 639006e..ea613f6 100644 --- a/smime/__init__.py +++ b/smime/__init__.py @@ -2,6 +2,6 @@ __author__ = 'G. B. Versiani' __license__ = 'Apache License (2.0)' -__version__ = '0.0.4' +__version__ = '0.1.0b1' __all__ = [__author__, __license__, __version__] From 026c6e95fdf8628b60422a3aa6bf9d3d0148e9df Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:44:55 +0100 Subject: [PATCH 07/12] minor fix for setuptools in setup.py file --- CHANGES.rst | 6 +++--- setup.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b2373fd..f620b38 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ CHANGES ======= -0.0.5 (unreleased) ------------------- +0.1.0b1 (unreleased) +-------------------- -- Nothing changed yet. +- Initial release. diff --git a/setup.py b/setup.py index e3ab77f..bbdcae8 100755 --- a/setup.py +++ b/setup.py @@ -48,5 +48,6 @@ test_suite='tests', extras_require={ 'test': test_requires - } + }, + zip_safe=False, ) From 7e4bf94d57fd290db381c9a830f436f106215fac Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:45:36 +0100 Subject: [PATCH 08/12] Preparing release 0.1.0b1 --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index f620b38..5104e17 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ CHANGES ======= -0.1.0b1 (unreleased) +0.1.0b1 (2019-01-06) -------------------- - Initial release. From 62a1e5f9f632b4393c9ebcd6ade05ce113b21721 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:49:14 +0100 Subject: [PATCH 09/12] manual version added --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bbdcae8..35e24ed 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( name='smime-py23', - version=__import__('smime').__version__, + version='0.1.0b1', description='Python S/MIME Toolkit', long_description=long_description, url='https://github.com/balena/python-smime', From 01982c3a9da6330717869c3a775062aacbdf178c Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:50:16 +0100 Subject: [PATCH 10/12] Back to development: 0.1.0b2 --- CHANGES.rst | 6 ++++++ setup.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5104e17..e0f8f5f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,12 @@ CHANGES ======= +0.1.0b2 (unreleased) +-------------------- + +- Nothing changed yet. + + 0.1.0b1 (2019-01-06) -------------------- diff --git a/setup.py b/setup.py index 35e24ed..d3b1995 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( name='smime-py23', - version='0.1.0b1', + version='0.1.0b2.dev0', description='Python S/MIME Toolkit', long_description=long_description, url='https://github.com/balena/python-smime', From 2a370dd634b7b93dce695e2b57d66d07f6e5a7b2 Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:54:58 +0100 Subject: [PATCH 11/12] revert post release things --- CHANGES.rst | 6 ------ setup.py | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index e0f8f5f..5104e17 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,12 +2,6 @@ CHANGES ======= -0.1.0b2 (unreleased) --------------------- - -- Nothing changed yet. - - 0.1.0b1 (2019-01-06) -------------------- diff --git a/setup.py b/setup.py index d3b1995..bbdcae8 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ test_requires = ['pytest','pytest-flake8', 'pytest-cov'] setup( name='smime-py23', - version='0.1.0b2.dev0', + version=__import__('smime').__version__, description='Python S/MIME Toolkit', long_description=long_description, url='https://github.com/balena/python-smime', From 532ba27be1ee225d387f5f553a028e0aec519e9b Mon Sep 17 00:00:00 2001 From: Md Nazrul Islam Date: Sun, 6 Jan 2019 12:57:09 +0100 Subject: [PATCH 12/12] back to development 1.0.0b2 --- CHANGES.rst | 6 ++++++ smime/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5104e17..05c58bc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,12 @@ CHANGES ======= +0.1.0b2 (unreleased) +-------------------- + +- Initial release. + + 0.1.0b1 (2019-01-06) -------------------- diff --git a/smime/__init__.py b/smime/__init__.py index ea613f6..5e5e165 100644 --- a/smime/__init__.py +++ b/smime/__init__.py @@ -2,6 +2,6 @@ __author__ = 'G. B. Versiani' __license__ = 'Apache License (2.0)' -__version__ = '0.1.0b1' +__version__ = '0.1.0b2' __all__ = [__author__, __license__, __version__]