From bde8cdc1285f5b5a07363255eb59e14703bcd10e Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Fri, 7 Jun 2019 18:32:14 +0300 Subject: [PATCH 01/11] Alpha v5 --- .travis.yml | 14 +- Jenkinsfile | 456 +++------------- README.md | 12 +- setup.py | 23 +- virgil_crypto/__init__.py | 5 +- virgil_crypto/access_token_signer.py | 34 +- virgil_crypto/card_crypto.py | 61 ++- virgil_crypto/crypto.py | 503 +++++++++++------- .../{tests/hashes => errors}/__init__.py | 7 +- .../virgil_crypto_error.py} | 44 +- virgil_crypto/hashes/__init__.py | 1 - virgil_crypto/hashes/fingerprint.py | 79 --- virgil_crypto/hashes/hash_algorithm.py | 25 +- virgil_crypto/keys/__init__.py | 6 +- virgil_crypto/keys/key_pair_type.py | 76 +-- .../keys/{key_pair.py => virgil_key_pair.py} | 2 +- .../{public_key.py => virgil_private_key.py} | 15 +- .../{private_key.py => virgil_public_key.py} | 15 +- virgil_crypto/private_key_exporter.py | 79 --- .../tests/access_token_signer_test.py | 8 +- virgil_crypto/tests/card_crypto_test.py | 15 +- virgil_crypto/tests/chunk_cipher_test.py | 88 --- virgil_crypto/tests/cipher_test.py | 55 +- virgil_crypto/tests/compatibility_test.py | 48 +- virgil_crypto/tests/crypto_test.py | 200 ++++--- .../tests/data/sdk_compatibility_data.json | 5 + .../tests/hashes/fingerprint_test.py | 55 -- .../tests/private_key_exporter_test.py | 76 --- virgil_crypto/tests/signer_test.py | 24 +- virgil_crypto/tests/stream_signer_test.py | 26 +- virgil_crypto/tests/virgil_key_pair_test.py | 84 --- 31 files changed, 765 insertions(+), 1376 deletions(-) rename virgil_crypto/{tests/hashes => errors}/__init__.py (89%) rename virgil_crypto/{streams.py => errors/virgil_crypto_error.py} (60%) delete mode 100644 virgil_crypto/hashes/fingerprint.py rename virgil_crypto/keys/{key_pair.py => virgil_key_pair.py} (95%) rename virgil_crypto/keys/{public_key.py => virgil_private_key.py} (76%) rename virgil_crypto/keys/{private_key.py => virgil_public_key.py} (76%) delete mode 100644 virgil_crypto/private_key_exporter.py delete mode 100644 virgil_crypto/tests/chunk_cipher_test.py delete mode 100644 virgil_crypto/tests/hashes/fingerprint_test.py delete mode 100644 virgil_crypto/tests/private_key_exporter_test.py delete mode 100644 virgil_crypto/tests/virgil_key_pair_test.py diff --git a/.travis.yml b/.travis.yml index cf23047..9c9a1e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ python: env: global: - - CDN_ARTIFACTS=$([ "$TRAVIS_BRANCH" == "master" ] && echo "virgil-crypto" || echo "virgil-crypto-dev") - OS_NAME=$(echo $TRAVIS_OS_NAME) matrix: @@ -48,17 +47,8 @@ before_install: | fi install: - - if [ -z "$PYTHON_VERSION" ]; then export PYTHON_VERSION=$(echo "$TRAVIS_PYTHON_VERSION" | sed -e 's/-dev//g'); fi - - echo $CDN_ARTIFACTS - - echo $TRAVIS_PYTHON_VERSION - - echo $PYTHON_VERSION - - wget https://cdn.virgilsecurity.com/$CDN_ARTIFACTS/VERSION - - sed -i -e 's/-dev//g' VERSION - - echo "virgil-crypto-$(cat VERSION)-python-${PYTHON_VERSION}-${OS_NAME}-*x86_64.tgz" - - wget -np -nd -r https://cdn.virgilsecurity.com/$CDN_ARTIFACTS/python/ -A "virgil-crypto-$(cat VERSION)-python-${PYTHON_VERSION}-${OS_NAME}-*x86_64.tgz" - - cd virgil_crypto && tar xzf ../*.tgz --strip=2 - - ls -la - - cd .. + - pip install virgil-crypto-lib + - pip install . script: - pwd diff --git a/Jenkinsfile b/Jenkinsfile index a50db1c..6e47f4c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,422 +1,96 @@ -def CRYPTO_VERSION = "undefined" - -stage('Get Artifacts crypto lib python'){ +// -------------------------------------------------------------------------- +// Configuration properties. +// -------------------------------------------------------------------------- +properties([ + parameters([ + booleanParam(name: 'DEPLOY_ARTIFACTS', defaultValue: false, + description: 'If branch = master and build succeeded then Python artifacts will be deployed to the Pip repository..') + ]) +]) + +stage('Grab SCM'){ node('master'){ clearContentUnix() checkout scm - - step ([$class: 'CopyArtifact', projectName: "$CRYPTO_ARTIFACTS_NAME", filter: 'install/python/**']); - step ([$class: 'CopyArtifact', projectName: "$CRYPTO_ARTIFACTS_NAME", filter: 'install/VERSION']); - if ("${env.CRYPTO_VERSION}" == "Default"){ - env.CRYPTO_VERSION = readFile("install/VERSION") - } - sh "rm install/VERSION" - stash excludes: '**/install/**', includes: '**', name: 'wrapper-source' - stash excludes: '*.sha256', includes: 'install/python/virgil-crypto-**-linux**', name: 'python-artifacts-linux' - stash excludes: '*.sha256', includes: 'install/python/virgil-crypto-**-windows**', name: 'python-artifacts-windows' - stash excludes: '*.sha256', includes: 'install/python/virgil-crypto-**-darwin**', name: 'python-artifacts-darwin' + stash includes: "**", name: "python_source" } } stage('Build'){ - echo("Version of Crypto build: $CRYPTO_VERSION") - def slaves = [:] - slaves['native-linux'] = createLinuxWheels("build-docker", "linux", CRYPTO_VERSION) - slaves['native-darwin'] = createLinuxWheels("build-docker", "osx", CRYPTO_VERSION) - slaves['native-windows'] = createLinuxWheels("build-docker", "windows", CRYPTO_VERSION) - parallel slaves -} - -stage('Artifacts Packing'){ - node('master'){ - clearContentUnix() - unstash 'linux-artifacts' - unstash 'osx-artifacts' - unstash 'windows-artifacts' - archiveArtifacts("dist/**") - } -} - -// Utility Functions - -def createLinuxWheels(slave, artifactType, CRYPTO_VERSION){ - return{ - if (artifactType == "linux"){ - node(slave){ - docker.image('python:2.7').inside("--user root"){ - clearContentUnix() - } - unstash 'wrapper-source' - unstash 'python-artifacts-linux' - def copiedFiles = [] - - //x64 - copiedFiles = unpackCryptoArtifactsLinux('python-2.7') - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.3") - docker.image("python:3.3").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.4") - docker.image("python:3.4").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.5") - docker.image("python:3.5").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.6") - docker.image("python:3.6").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.7") - docker.image("python:3.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_x86_64" - sh "python setup.py bdist_egg --plat-name manylinux1_x86_64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - //x86 - copiedFiles = unpackCryptoArtifactsLinux('python-2.7') - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.3") - docker.image("python:3.3").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.4") - docker.image("python:3.4").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.5") - docker.image("python:3.5").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.6") - docker.image("python:3.6").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.7") - docker.image("python:3.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name manylinux1_i686" - sh "python setup.py bdist_egg --plat-name manylinux1_i686" - cleanBuildDirectoriesLinux(copiedFiles) - } - - stash includes: "dist/**", name: "linux-artifacts" - } + node("build-docker"){ + // Build python wheels + docker.image("python:3.7").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "pip install wheel" + sh "python setup.py bdist_wheel --universal" } - if (artifactType == "osx"){ - node(slave){ - docker.image('python:2.7').inside("--user root"){ - clearContentUnix() - } - unstash 'wrapper-source' - unstash 'python-artifacts-darwin' - def copiedFiles = [] - - copiedFiles = unpackCryptoArtifactsLinux('python-2.7') - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name macosx_10_12_intel" - sh "python setup.py bdist_egg --plat-name macosx_10_12_intel" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.4") - docker.image("python:3.4").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name macosx_10_12_intel" - sh "python setup.py bdist_egg --plat-name macosx_10_12_intel" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.5") - docker.image("python:3.5").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name macosx_10_12_intel" - sh "python setup.py bdist_egg --plat-name macosx_10_12_intel" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.6") - docker.image("python:3.6").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name macosx_10_12_intel" - sh "python setup.py bdist_egg --plat-name macosx_10_12_intel" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.7") - docker.image("python:3.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name macosx_10_12_intel" - sh "python setup.py bdist_egg --plat-name macosx_10_12_intel" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - //Fixing Python ABI tag - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh 'for file in dist/*-cp27mu-*.whl; do echo $file | mv $file $(sed -r \'s/cp27mu/cp27m/g\'); done' - } - - stash includes: "dist/**", name: "osx-artifacts" - } + // Build python eggs + docker.image("python:2.7").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "python setup.py bdist_egg" } - if (artifactType == "windows"){ - node(slave){ - docker.image('python:2.7').inside("--user root"){ - clearContentUnix() - } - unstash 'wrapper-source' - unstash 'python-artifacts-windows' - def copiedFiles = [] - - //x64 - copiedFiles = unpackCryptoArtifactsLinux('python-2.7', "x64") - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.3", "x64") - docker.image("python:3.3").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.4", "x64") - docker.image("python:3.4").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.5", "x64") - docker.image("python:3.5").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.6", "x64") - docker.image("python:3.6").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.7", "x64") - docker.image("python:3.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win_amd64" - sh "python setup.py bdist_egg --plat-name win_amd64" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - //x86 - copiedFiles = unpackCryptoArtifactsLinux('python-2.7', "x86") - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.3", "x86") - docker.image("python:3.3").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.4", "x86") - docker.image("python:3.4").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } - - - copiedFiles = unpackCryptoArtifactsLinux("python-3.5", "x86") - docker.image("python:3.5").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } - - copiedFiles = unpackCryptoArtifactsLinux("python-3.6", "x86") - docker.image("python:3.6").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } + docker.image("python:3.4").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "python setup.py bdist_egg" + } - copiedFiles = unpackCryptoArtifactsLinux("python-3.7", "x86") - docker.image("python:3.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh "pip install wheel" - sh "python setup.py bdist_wheel --plat-name win32" - sh "python setup.py bdist_egg --plat-name win32" - cleanBuildDirectoriesLinux(copiedFiles) - } + docker.image("python:3.5").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "python setup.py bdist_egg" + } - //Fixing Python ABI tag - docker.image("python:2.7").inside("--user root --env CRYPTO_VERSION=$CRYPTO_VERSION"){ - sh 'for file in dist/*-cp27mu-*.whl; do echo $file | mv $file $(sed -r \'s/cp27mu/cp27m/g\'); done' - } + docker.image("python:3.6").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "python setup.py bdist_egg" + } - stash includes: "dist/**", name: "windows-artifacts" - } + docker.image("python:3.7").inside("--user root"){ + cleanPythonPackageBuildDirectoriesLinux() + sh "python setup.py bdist_egg" } + stash includes: "dist/**", name: "python-packages" } } - -def unpackCryptoArtifactsLinux(pythonVersionToUnpack){ - def copiedFiles = [] - sh "mkdir $WORKSPACE/temp_vars" - dir("install/python"){ - sh "ls -1 | grep $pythonVersionToUnpack | grep -E '^.*tgz\$' > $WORKSPACE/temp_vars/artifact_to_unpack.txt" - def artifactToUnpack = readFile("$WORKSPACE/temp_vars/artifact_to_unpack.txt").trim() - def artifactName = "" - if (artifactToUnpack.endsWith(".tgz")){ - artifactName = artifactToUnpack.replace('.tgz', '') - sh "tar xfz $artifactToUnpack" - } else { - artifactName = artifactToUnpack.replace('.zip', '') - sh "unzip $artifactToUnpack" - } - - if (artifactName){ - dir("$artifactName/lib/"){ - sh "ls -1 > $WORKSPACE/temp_vars/copied_file.txt" - } - copiedFiles << readFile("$WORKSPACE/temp_vars/copied_file.txt").trim() - dir("$artifactName/api/"){ - sh "ls -1 > $WORKSPACE/temp_vars/copied_file.txt" - } - copiedFiles << readFile("$WORKSPACE/temp_vars/copied_file.txt").trim() - sh "cp $artifactName/lib/* $WORKSPACE/virgil_crypto/" - sh "cp $artifactName/api/* $WORKSPACE/virgil_crypto/" - dir("$WORKSPACE/temp_vars"){ - deleteDir() - } - } else { - print("WARNING: artifactName is EMPTY!") - } +stage('Artifacts Packing'){ + node('master'){ + clearContentUnix() + unstash 'python-packages' + archiveArtifacts("dist/**") } - return copiedFiles } -def unpackCryptoArtifactsLinux(pythonVersionToUnpack, platformArch){ - def copiedFiles = [] - sh "mkdir $WORKSPACE/temp_vars" - dir("install/python"){ - sh "ls -1 | grep $pythonVersionToUnpack | grep -E '^.*$platformArch.*zip\$' > $WORKSPACE/temp_vars/artifact_to_unpack.txt" - def artifactToUnpack = readFile("$WORKSPACE/temp_vars/artifact_to_unpack.txt").trim() - def artifactName = "" - if (artifactToUnpack.endsWith(".tgz")){ - artifactName = artifactToUnpack.replace('.tgz', '') - sh "tar xfz $artifactToUnpack" - } else { - artifactName = artifactToUnpack.replace('.zip', '') - sh "unzip $artifactToUnpack" +stage('Deploy Packages'){ + node('master') { + clearContentUnix() + unstash 'python-packages' + + echo "DEPLOY_ARTIFACTS = ${params.DEPLOY_ARTIFACTS}" + if (!params.DEPLOY_ARTIFACTS) { + echo "Skipped due to the false parameter: DEPLOY_ARTIFACTS" + return } - if (artifactName){ - dir("$artifactName/lib/"){ - sh "ls -1 > $WORKSPACE/temp_vars/copied_file.txt" - } - copiedFiles << readFile("$WORKSPACE/temp_vars/copied_file.txt").trim() - dir("$artifactName/api/"){ - sh "ls -1 > $WORKSPACE/temp_vars/copied_file.txt" - } - copiedFiles << readFile("$WORKSPACE/temp_vars/copied_file.txt").trim() - sh "cp $artifactName/lib/* $WORKSPACE/virgil_crypto/" - sh "cp $artifactName/api/* $WORKSPACE/virgil_crypto/" - dir("$WORKSPACE/temp_vars"){ - deleteDir() - } + if (env.BRANCH_NAME == "master") { + sh """ + env + twine upload dist/* + """ } else { - print("WARNING: artifactName is EMPTY!") + echo "Skipped due to the branch: $BRANCH_NAME is not master" + return } } - return copiedFiles } -def cleanBuildDirectoriesLinux(copiedFiles){ - if (copiedFiles){ - for (copFile in copiedFiles){ - sh "rm virgil_crypto/$copFile" - } - sh "rm -r ./build" - sh "rm -r *.egg-info" - } else { - print("WARNING! Nothing to do copiedFiles EMPTY!") - } +// Utility Functions + +def cleanPythonPackageBuildDirectoriesLinux(){ + sh "find virgil_crypto_lib/ -name '*.pyc' -delete" + sh "rm -rf ./build" + sh "rm -rf *.egg-info" } def clearContentUnix() { diff --git a/README.md b/README.md index d431f55..a095a0c 100644 --- a/README.md +++ b/README.md @@ -31,24 +31,24 @@ Generate a Private Key with the default algorithm (EC_X25519): from virgil_crypto import VirgilCrypto crypto = VirgilCrypto() -key_pair = crypto.generate_keys() +key_pair = crypto.generate_key_pair() ``` -#### Generate and verify a signature +#### Generate and verify_signature a signature -Generate signature and sign data with a private key: +Generate signature and generate_signature data with a private key: ```python from virgil_crypto import VirgilCrypto crypto = VirgilCrypto() -key_pair = crypto.generate_keys() +key_pair = crypto.generate_key_pair() sender_private_key = key_pair.private_key message_to_sign = "Hello, Bob!" data_to_sign = message_to_sign.encode() -signature = crypto.sign(data_to_sign, sender_private_key) +signature = crypto.generate_signature(data_to_sign, sender_private_key) ``` Verify a signature with a public key: @@ -58,7 +58,7 @@ from virgil_crypto import VirgilCrypto crypto = VirgilCrypto() -verified = crypto.verify(data_to_sign, signature, sender_public_key) +verified = crypto.verify_signature(data_to_sign, signature, sender_public_key) ``` #### Encrypt and decrypt data diff --git a/setup.py b/setup.py index 328306b..35c92e6 100644 --- a/setup.py +++ b/setup.py @@ -1,24 +1,10 @@ -import os +from virgil_crypto import __version__ from setuptools import setup, find_packages -from setuptools.dist import Distribution - -crypto_version = os.getenv("CRYPTO_VERSION").split(".") -crypto_version[0] = crypto_version[0].replace("2", "3") - - -class BinaryDistribution(Distribution): - """Distribution which always forces a binary package with platform name""" - - def has_ext_modules(self): - return True - - def is_pure(self): - return False setup( name="virgil-crypto", - version=".".join(crypto_version), + version=__version__, author="Virgil Security", url="https://virgilsecurity.com/", classifiers=[ @@ -34,6 +20,7 @@ def is_pure(self): "Programming Language :: Python :: 3.7", "Topic :: Security :: Cryptography", ], + install_requires=["virgil-crypto-lib"], license="BSD", include_package_data=True, zip_safe=False, @@ -45,12 +32,8 @@ def is_pure(self): Virgil Security provides a set of APIs for adding security to any application. In a few simple steps you can encrypt communication, securely store data, provide passwordless login, and ensure data integrity. Virgil Python Crypto Library is a high-level cryptographic library that allows you to perform all necessary operations for secure storing and transferring data and everything required to become HIPAA and GDPR compliant. """, - distclass=BinaryDistribution, packages=find_packages(), package_data={"virgil_crypto": [ - "_virgil_crypto_python.so", - "virgil_crypto_python.py", - "_virgil_crypto_python.pyd", "tests/*", "tests/data/*.json" ]} diff --git a/virgil_crypto/__init__.py b/virgil_crypto/__init__.py index 362a45d..0f19ae7 100644 --- a/virgil_crypto/__init__.py +++ b/virgil_crypto/__init__.py @@ -32,7 +32,6 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from .virgil_crypto_python import * -from .streams import * +__version__ = "5.0.0" + from .crypto import VirgilCrypto -from .private_key_exporter import PrivateKeyExporter diff --git a/virgil_crypto/access_token_signer.py b/virgil_crypto/access_token_signer.py index 5239287..9a51e05 100644 --- a/virgil_crypto/access_token_signer.py +++ b/virgil_crypto/access_token_signer.py @@ -31,7 +31,7 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from virgil_crypto.keys import PrivateKey, PublicKey +from virgil_crypto.keys import VirgilPrivateKey, VirgilPublicKey from virgil_crypto import VirgilCrypto @@ -46,36 +46,52 @@ def __init__(self, crypto=VirgilCrypto()): self.__crypto = crypto def generate_token_signature(self, token, private_key): - # type: (Union[bytes, bytearray], PrivateKey) -> bytearray + # type: (Union[bytes, bytearray], VirgilPrivateKey) -> bytearray """Generate signature for Access token + Args: - token: Access Token. + token: Access Token bytes. private_key: Signer Private Key. + Returns: Signature bytes. + + Raises: + ValueError: if token or private key missing or malformed """ if not private_key: raise ValueError("Missing private key") - if not isinstance(private_key, PrivateKey): + if not token: + raise ValueError("Missing token for sign") + + if not isinstance(private_key, VirgilPrivateKey): raise ValueError("private_key must be a VirgilPrivateKey type") - return self.__crypto.sign(token, private_key) + return self.__crypto.generate_signature(token, private_key) def verify_token_signature(self, signature, token, public_key): - # type: (Union[bytes, bytearray], Union[bytes, bytearray], PublicKey) -> bool + # type: (Union[bytes, bytearray], Union[bytes, bytearray], VirgilPublicKey) -> bool """Verify Access Token signature + Args: - signature: Token signature + signature: Token signature bytes token: Access Token public_key: Signer Public Key + Returns: True if signature is valid, False otherwise. + + Raises: + ValueError: if public key or token missed or malformed. """ - if not isinstance(public_key, PublicKey): + if not isinstance(public_key, VirgilPublicKey): raise ValueError("public_key must be a VirgilPublicKey type") - return self.__crypto.verify( + if not token: + raise ValueError("Missing token to verify") + + return self.__crypto.verify_signature( token, signature, public_key ) diff --git a/virgil_crypto/card_crypto.py b/virgil_crypto/card_crypto.py index d30a082..de400c1 100644 --- a/virgil_crypto/card_crypto.py +++ b/virgil_crypto/card_crypto.py @@ -34,7 +34,7 @@ from virgil_crypto.hashes import HashAlgorithm from virgil_crypto import VirgilCrypto -from virgil_crypto.keys import PrivateKey, PublicKey +from virgil_crypto.keys import VirgilPrivateKey, VirgilPublicKey class CardCrypto(object): @@ -46,75 +46,116 @@ def __init__(self, crypto=VirgilCrypto()): self.__crypto = crypto def generate_signature(self, data, private_key): - # type: (Union[bytes, bytearray], PrivateKey) -> bytearray + # type: (Union[bytes, bytearray], VirgilPrivateKey) -> bytearray """Signs the specified data using Private key. + Args: data: raw data bytes for signing. private_key: private key for signing. + Returns: Signature bytes. + + Raises: + ValueError: if data or private key missing or malformed """ + if not data: + raise ValueError("Missing data for signing") + if not private_key: raise ValueError("Missing private key") - if not isinstance(private_key, PrivateKey): + if not isinstance(private_key, VirgilPrivateKey): raise ValueError("private_key must be a VirgilPrivateKey type") - return self.__crypto.sign(data, private_key) + return self.__crypto.generate_signature(data, private_key) def verify_signature(self, signature, data, public_key): - # type: (Union[bytes, bytearray], Union[bytes, bytearray], PublicKey) -> bool + # type: (Union[bytes, bytearray], Union[bytes, bytearray], VirgilPublicKey) -> bool """Verifies the specified signature using original data and signer's public key. + Args: - data: original data bytes for verification. signature: signature bytes for verification. + data: original data bytes for verification. public_key: signer public key for verification. + Returns: True if signature is valid, False otherwise. + + Raises: + ValueError: if data, signature, public key missing or malformed. """ - if not isinstance(public_key, PublicKey): + if not signature: + raise ValueError("Missing signature") + + if not data: + raise ValueError("Missing data for signature verify") + + if not isinstance(public_key, VirgilPublicKey): raise ValueError("public_key must be a VirgilPublicKey type") - return self.__crypto.verify( + return self.__crypto.verify_signature( data, signature, public_key ) def export_public_key(self, public_key): - # type: (PublicKey) -> bytearray + # type: (VirgilPublicKey) -> bytearray """Exports the Public key into material representation. + Args: public_key: public key for export. + Returns: Key material representation bytes. + + Raises: + ValueError: if public key missing or malformed. """ if not public_key: raise ValueError("Missing public key") + if public_key.public_key is None or public_key.identifier is None or public_key.key_type is None: + raise ValueError("Public Key is not complete.") return self.__crypto.export_public_key(public_key) def import_public_key(self, data): - # type: (Union[bytes, bytearray]) -> PublicKey + # type: (Union[bytes, bytearray]) -> VirgilPublicKey """Imports the Public key from material representation. + Args: data: key material representation bytes. + Returns: Imported public key. + + Raises: + ValueError: if key data missing """ + if not data: + raise ValueError("Key data missing") return self.__crypto.import_public_key(data) def generate_sha512(self, data): # type: (Union[bytes, bytearray]) -> bytearray """Computes the sha512 hash of specified data. + Args: data: data bytes for fingerprint calculation. + Returns: Hash bytes. + + Raises: + ValueError: if data missed. """ + if not data: + raise ValueError("Missed data for fingerprint generation") return self.__crypto.compute_hash(data, HashAlgorithm.SHA512) @property def crypto(self): """ Gets Virgil Crypto. + Returns: Card Crypto """ diff --git a/virgil_crypto/crypto.py b/virgil_crypto/crypto.py index 6d3443b..6ec2092 100644 --- a/virgil_crypto/crypto.py +++ b/virgil_crypto/crypto.py @@ -31,21 +31,15 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +from virgil_crypto_lib.foundation import CtrDrbg, Signer, Sha512, Verifier, Aes256Gcm, RecipientCipher, KeyProvider, \ + KeyMaterialRng, PublicKey, KeyAsn1Serializer, AlgId -from virgil_crypto import VirgilCipher -from virgil_crypto import VirgilKeyPair -from virgil_crypto import VirgilSigner -from virgil_crypto import VirgilStreamSigner -from virgil_crypto import VirgilStreamDataSink -from virgil_crypto import VirgilStreamDataSource -from virgil_crypto import VirgilHash -from virgil_crypto.keys import KeyPair +from virgil_crypto.errors.virgil_crypto_error import VirgilCryptoErrors +from virgil_crypto.keys import VirgilKeyPair from virgil_crypto.keys import KeyPairType -from virgil_crypto.keys import PrivateKey -from virgil_crypto.keys import PublicKey +from virgil_crypto.keys import VirgilPrivateKey +from virgil_crypto.keys import VirgilPublicKey from virgil_crypto.hashes import HashAlgorithm -from virgil_crypto.hashes import Fingerprint -from virgil_crypto import VirgilStreamCipher class VirgilCrypto(object): @@ -55,12 +49,17 @@ class VirgilCrypto(object): signature generation and verification, and encryption and decryption """ - def __init__(self): - self.signature_hash_algorithm = HashAlgorithm.SHA512 - self.use_sha256_fingerprints = False - self.key_pair_type = KeyPairType.Default - _CUSTOM_PARAM_KEY_SIGNATURE = None + CUSTOM_PARAM_KEY_SIGNATURE = bytearray("VIRGIL-DATA-SIGNATURE".encode()) + CUSTOM_PARAM_KEY_SIGNER_ID = bytearray("VIRGIL-DATA-SIGNER-ID".encode()) + + def __init__(self, default_key_pair_type=KeyPairType.ED25519, use_sha256_fingerprints=False): + rng = CtrDrbg() + rng.setup_defaults() + self.rng = rng + self.key_pair_type = default_key_pair_type + self.use_sha256_fingerprints = use_sha256_fingerprints + self.chunk_size = 1024 class SignatureIsNotValid(Exception): """Exception raised when Signature is not valid""" @@ -83,57 +82,80 @@ def strtobytes(source): """ return tuple(bytearray(source, 'utf-8')) - def generate_keys(self, key_pair_type=KeyPairType.Default): - # type: (int) -> KeyPair + def generate_key_pair(self, key_type=KeyPairType.ED25519, seed=None): + # type: (KeyPairType.KeyType, Union[Tuple[int], bytearray]) -> VirgilKeyPair """Generates asymmetric key pair that is comprised of both public and private keys by specified type. Args: - key_pair_type: type of the generated keys. + key_type: type of the generated keys. The possible values can be found in KeyPairType enum. + seed: random value used to generate key Returns: Generated key pair. """ - native_type = KeyPairType.convert_to_native(key_pair_type) - native_key_pair = VirgilKeyPair.generate(native_type) - key_pair_id = self.compute_public_key_hash(native_key_pair.publicKey()) - private_key = PrivateKey( - identifier=key_pair_id, - raw_key=VirgilKeyPair.privateKeyToDER(native_key_pair.privateKey()) - ) - public_key = PublicKey( - identifier=key_pair_id, - raw_key=VirgilKeyPair.publicKeyToDER(native_key_pair.publicKey()) + + if seed: + if KeyMaterialRng.KEY_MATERIAL_LEN_MIN > len(seed) > KeyMaterialRng.KEY_MATERIAL_LEN_MAX: + raise VirgilCryptoErrors.INVALID_SEED_SIZE + key_material_rng = KeyMaterialRng() + key_material_rng.reset_key_material(seed) + rng = key_material_rng + else: + rng = self.rng + + key_provider = KeyProvider() + + key_provider.set_random(rng) + + if key_type.rsa_bitlen: + key_provider.set_rsa_params(key_type.rsa_bitlen) + + key_provider.setup_defaults() + + private_key = key_provider.generate_private_key(key_type.alg_id) + public_key = private_key.extract_public_key() + + key_id = self.compute_public_key_identifier(public_key) + + return VirgilKeyPair( + private_key=VirgilPrivateKey(identifier=key_id, private_key=private_key, key_type=key_type), + public_key=VirgilPublicKey(identifier=key_id, public_key=public_key, key_type=key_type) ) - return KeyPair(private_key=private_key, public_key=public_key) - def import_private_key(self, key_data, password=None): - # type: (Union[Tuple[int], List[int]], Optional[str]) -> PrivateKey - """Imports the Private key from material representation. + def import_private_key(self, key_data): + # type: (Union[Tuple[int], List[int]], bytearray) -> VirgilKeyPair + """Imports private key from DER or PEM format Args: - key_data: key material representation bytes. - password: private key password, None by default. + key_data: Private key in DER or PEM format. Returns: - Imported private key. + VirgilKeyPair. """ - decrypted_private_key = None - if not password: - decrypted_private_key = VirgilKeyPair.privateKeyToDER(key_data) + key_provider = KeyProvider() + key_provider.set_random(self.rng) + + key_provider.setup_defaults() + + private_key = key_provider.import_private_key(bytearray(key_data)) + + if private_key.alg_id() == AlgId.RSA: + key_type = KeyPairType.KeyType(private_key.alg_id(), private_key.bit_length()) else: - decrypted_private_key = VirgilKeyPair.decryptPrivateKey( - key_data, - self.strtobytes(password) - ) + key_type = KeyPairType.KeyType(private_key.alg_id()) - public_key_data = VirgilKeyPair.extractPublicKey(decrypted_private_key, []) - key_pair_id = self.compute_public_key_hash(public_key_data) - private_key_data = VirgilKeyPair.privateKeyToDER(decrypted_private_key) - return PrivateKey(identifier=key_pair_id, raw_key=private_key_data) + public_key = private_key.extract_public_key() + + key_id = self.compute_public_key_identifier(public_key) + + return VirgilKeyPair( + private_key=VirgilPrivateKey(identifier=key_id, private_key=private_key, key_type=key_type), + public_key=VirgilPublicKey(identifier=key_id, public_key=public_key, key_type=key_type) + ) def import_public_key(self, key_data): - # type: (Union[Tuple[int], List[int]]) -> PublicKey + # type: (Union[Tuple[int], List[int]]) -> VirgilPublicKey """Imports the Public key from material representation. Args: @@ -142,34 +164,45 @@ def import_public_key(self, key_data): Returns: Imported public key. """ - key_pair_id = self.compute_public_key_hash(key_data) - public_key_data = VirgilKeyPair.publicKeyToDER(key_data) - return PublicKey(identifier=key_pair_id, raw_key=public_key_data) + if not key_data: + raise ValueError("Key data missing") - def export_private_key(self, private_key, password=None): - # type: (PrivateKey, Optional[str]) -> Tuple[int] - """Exports the Private key into material representation. + key_provider = KeyProvider() + key_provider.set_random(self.rng) + key_provider.setup_defaults() + + public_key = key_provider.import_public_key(bytearray(key_data)) + if public_key.alg_id() == AlgId.RSA: + key_type = KeyPairType.KeyType(public_key.alg_id(), public_key.bit_length()) + else: + key_type = KeyPairType.KeyType(public_key.alg_id()) + + key_id = self.compute_public_key_identifier(public_key) + return VirgilPublicKey( + identifier=key_id, + public_key=public_key, + key_type=key_type + ) + + @staticmethod + def export_private_key(private_key): + # type: (VirgilPrivateKey) -> Union[Tuple[int], bytearray] + """Exports private key to DER format Args: private_key: private key for export. - password: private key password, None by default. + Returns: - Key material representation bytes. + Private key in DER format """ - if not password: - return VirgilKeyPair.privateKeyToDER(private_key.raw_key) - - password_bytes = self.strtobytes(password) - private_key_data = VirgilKeyPair.encryptPrivateKey( - private_key.raw_key, - password_bytes - ) - return VirgilKeyPair.privateKeyToDER(private_key_data, password_bytes) + serializer = KeyAsn1Serializer() + serializer.setup_defaults() + return serializer.serialize_private_key(private_key.private_key) @staticmethod def export_public_key(public_key): - # type: (PublicKey) -> Tuple[int] + # type: (VirgilPrivateKey) -> Union[Tuple[int], bytearray] """Exports the Public key into material representation. Args: @@ -178,11 +211,14 @@ def export_public_key(public_key): Returns: Key material representation bytes. """ - return VirgilKeyPair.publicKeyToDER(public_key.raw_key) + serializer = KeyAsn1Serializer() + serializer.setup_defaults() + + return serializer.serialize_public_key(public_key.public_key) @staticmethod def extract_public_key(private_key): - # type: (PrivateKey) -> PublicKey + # type: (VirgilPrivateKey) -> VirgilPublicKey """Extracts the Public key from Private key. Args: @@ -191,16 +227,14 @@ def extract_public_key(private_key): Returns: Exported public key. """ - public_key_data = VirgilKeyPair.extractPublicKey(private_key.raw_key, []) - public_key = PublicKey( + return VirgilPublicKey( identifier=private_key.identifier, - raw_key=VirgilKeyPair.publicKeyToDER(public_key_data) + public_key=private_key.private_key.extract_public_key(), + key_type=private_key.key_type ) - return public_key - @staticmethod - def encrypt(data, *recipients): - # type: (Union[Tuple[int], List[int]], List[PublicKey]) -> Tuple[int] + def encrypt(self, data, *recipients): + # type: (Union[Tuple[int], List[int], bytearray], List[VirgilPublicKey]) -> Union[Tuple[int], bytearray] """Encrypts the specified data using recipients Public keys. Args: @@ -210,14 +244,24 @@ def encrypt(data, *recipients): Returns: Encrypted data bytes. """ - cipher = VirgilCipher() + aes_gcm = Aes256Gcm() + cipher = RecipientCipher() + cipher.set_encryption_cipher(aes_gcm) + cipher.set_random(self.rng) + for public_key in recipients: - cipher.addKeyRecipient(public_key.identifier, public_key.raw_key) - return cipher.encrypt(data) + cipher.add_key_recipient(public_key.identifier, public_key.public_key) + + cipher.start_encryption() + result = cipher.pack_message_info() + result += cipher.process_encryption(bytearray(data)) + result += cipher.finish_encryption() + + return result @staticmethod - def decrypt(cipher_data, private_key): - # type: (Union[Tuple[int], List[int]], PrivateKey) -> Tuple[int] + def decrypt(data, private_key): + # type: (Union[Tuple[int], List[int]], VirgilPrivateKey) -> Tuple[int] """Decrypts the specified data using Private key. Args: @@ -227,69 +271,102 @@ def decrypt(cipher_data, private_key): Returns: Decrypted data bytes. """ - cipher = VirgilCipher() - decrypted_data = cipher.decryptWithKey( - cipher_data, + cipher = RecipientCipher() + + cipher.start_decryption_with_key( private_key.identifier, - private_key.raw_key + private_key.private_key, + bytearray() ) - return decrypted_data + result = bytearray() + result += cipher.process_decryption(bytearray(data)) + result += cipher.finish_decryption() + return result def sign_then_encrypt(self, data, private_key, *recipients): - # type: (Union[Tuple[int], List[int]], PrivateKey, List[PublicKey]) -> Tuple[int] + # type: (Union[Tuple[int], List[int], bytearray], VirgilPrivateKey, List[VirgilPublicKey]) -> Union[Tuple[int], bytearray] """Signs and encrypts the data. Args: data: data bytes for signing and encryption. - private_key: private key to sign the data. + private_key: sender private key recipients: list of recipients' public keys. Used for data encryption. Returns: Signed and encrypted data bytes. """ - signer = VirgilSigner(self.signature_hash_algorithm) - signature = signer.sign(data, private_key.raw_key) - cipher = VirgilCipher() - custom_data = cipher.customParams() - custom_data.setData( - self.custom_param_key_signature, - signature - ) - for public_key in recipients: - cipher.addKeyRecipient(public_key.identifier, public_key.raw_key) - return cipher.encrypt(data) + signature = self.generate_signature(bytearray(data), private_key) + + aes_gcm = Aes256Gcm() + cipher = RecipientCipher() + + cipher.set_encryption_cipher(aes_gcm) + cipher.set_random(self.rng) + + for recipient in recipients: + cipher.add_key_recipient(recipient.identifier, recipient.public_key) - def decrypt_then_verify(self, data, private_key, public_key): - # type: (Union[Tuple[int], List[int]], PrivateKey, PublicKey) -> Tuple[int] + cp = cipher.custom_params() + cp.add_data(VirgilCrypto.CUSTOM_PARAM_KEY_SIGNATURE, signature) + cp.add_data(VirgilCrypto.CUSTOM_PARAM_KEY_SIGNER_ID, private_key.identifier) + + cipher.start_encryption() + result = cipher.pack_message_info() + result += cipher.process_encryption(bytearray(data)) + result += cipher.finish_encryption() + + return result + + def decrypt_then_verify(self, data, private_key, signers_public_keys): + # type: (Union[Tuple[int], List[int], bytearray], VirgilPrivateKey, Union[List[VirgilPublicKey], VirgilPublicKey]) -> Union[Tuple[int], bytearray] """Decrypts and verifies the data. Args: data: encrypted data bytes. private_key: private key for decryption. - public_key: public key for verification. - + signers_public_keys: List of possible signers public keys. + WARNING: data should have signature of ANY public key from list. Returns: Decrypted data bytes. Raises: - SignatureIsNotValid: if signature is not verified. + VirgilCryptoError: if signature is not verified. """ - cipher = VirgilCipher() - decrypted_data = cipher.decryptWithKey( - data, - private_key.identifier, - private_key.raw_key - ) - signature = cipher.customParams().getData(self.custom_param_key_signature) - is_valid = self.verify(decrypted_data, signature, public_key) + + cipher = RecipientCipher() + + cipher.start_decryption_with_key(private_key.identifier, private_key.private_key, bytearray()) + result = bytearray() + + result += cipher.process_decryption(bytearray(data)) + result += cipher.finish_decryption() + + if isinstance(signers_public_keys, VirgilPublicKey): + signer_public_key = signers_public_keys + else: + try: + signer_id = bytearray(cipher.custom_params().find_data(VirgilCrypto.CUSTOM_PARAM_KEY_SIGNER_ID)) + except Exception: + raise VirgilCryptoErrors.SIGNER_NOT_FOUND + + filtered_public_keys = list(filter(lambda x: x.identifier == signer_id, signers_public_keys)) + if not filtered_public_keys: + raise VirgilCryptoErrors.SIGNER_NOT_FOUND + + signer_public_key = filtered_public_keys[0] + + signature = bytearray(cipher.custom_params().find_data(VirgilCrypto.CUSTOM_PARAM_KEY_SIGNATURE)) + + is_valid = self.verify_signature(result, signature, signer_public_key) if not is_valid: - raise self.SignatureIsNotValid() - return decrypted_data + raise VirgilCryptoErrors.SIGNATURE_NOT_VERIFIED + return result - def sign(self, data, private_key): - # type: (Union[Tuple[int], List[int]], PrivateKey) -> Tuple[int] - """Signs the specified data using Private key. + @staticmethod + def generate_signature(data, private_key): + # type: (Union[Tuple[int], List[int], bytearray], VirgilPrivateKey) -> Union[Tuple[int], bytearray] + """Generates digital signature of data using private key Args: data: raw data bytes for signing. @@ -298,29 +375,33 @@ def sign(self, data, private_key): Returns: Signature bytes. """ - signer = VirgilSigner(self.signature_hash_algorithm) - signature = signer.sign(data, private_key.raw_key) + signer = Signer() + signer.set_hash(Sha512()) + signer.reset() + signer.update(bytearray(data)) + signature = signer.sign(private_key.private_key) return signature - def verify(self, data, signature, signer_public_key): - # type: (Union[Tuple[int], List[int]], Union[Tuple[int], List[int]], PublicKey) -> bool + @staticmethod + def verify_signature(data, signature, public_key): + # type: (Union[Tuple[int], List[int], bytearray], Union[Tuple[int], List[int], bytearray], VirgilPublicKey) -> bool """Verifies the specified signature using original data and signer's public key. Args: data: original data bytes for verification. signature: signature bytes for verification. - signer_public_key: signer public key for verification. + public_key: signer public key for verification. Returns: True if signature is valid, False otherwise. """ - signer = VirgilSigner(self.signature_hash_algorithm) - is_valid = signer.verify(data, signature, signer_public_key.raw_key) - return is_valid + verifier = Verifier() + verifier.reset(bytearray(signature)) + verifier.update(bytearray(data)) + return verifier.verify(public_key.public_key) - @staticmethod - def encrypt_stream(input_stream, output_stream, *recipients): - # type: (io.IOBase, io.IOBase, List[PublicKey]) -> None + def encrypt_stream(self, input_stream, output_stream, *recipients): + # type: (io.IOBase, io.IOBase, List[VirgilPublicKey]) -> None """Encrypts the specified stream using recipients Public keys. Args: @@ -330,16 +411,32 @@ def encrypt_stream(input_stream, output_stream, *recipients): """ - cipher = VirgilStreamCipher() + aes_gcm = Aes256Gcm() + cipher = RecipientCipher() + + cipher.set_encryption_cipher(aes_gcm) + cipher.set_random(self.rng) + for public_key in recipients: - cipher.addKeyRecipient(public_key.identifier, public_key.raw_key) - source = VirgilStreamDataSource(input_stream) - sink = VirgilStreamDataSink(output_stream) - cipher.encrypt(source, sink) + cipher.add_key_recipient(public_key.identifier, public_key.public_key) - @staticmethod - def decrypt_stream(input_stream, output_stream, private_key): - # type: (io.IOBase, io.IOBase, PrivateKey) -> None + cipher.start_encryption() + + msg_info = cipher.pack_message_info() + + if output_stream.closed: + output_stream.open() + + output_stream.write(msg_info) + + self.__for_each_chunk_output(input_stream, output_stream, cipher.process_encryption) + + finish = cipher.finish_encryption() + + output_stream.write(finish) + + def decrypt_stream(self, input_stream, output_stream, private_key): + # type: (io.IOBase, io.IOBase, VirgilPrivateKey) -> None """Decrypts the specified stream using Private key. Args: @@ -348,18 +445,20 @@ def decrypt_stream(input_stream, output_stream, private_key): private_key: private key for decryption. """ - cipher = VirgilStreamCipher() - source = VirgilStreamDataSource(input_stream) - sink = VirgilStreamDataSink(output_stream) - cipher.decryptWithKey( - source, - sink, + cipher = RecipientCipher() + cipher.start_decryption_with_key( private_key.identifier, - private_key.raw_key + private_key.private_key, + bytearray() ) - def sign_stream(self, input_stream, private_key): - # type: (io.IOBase, PrivateKey) -> Tuple(*int) + self.__for_each_chunk_output(input_stream, output_stream, cipher.process_decryption) + + finish = cipher.finish_decryption() + output_stream.write(finish) + + def generate_stream_signature(self, input_stream, private_key): + # type: (Type[io.IOBase], VirgilPrivateKey) -> Tuple(*int) """Signs the specified stream using Private key. Args: @@ -369,13 +468,17 @@ def sign_stream(self, input_stream, private_key): Returns: Signature bytes. """ - signer = VirgilStreamSigner(self.signature_hash_algorithm) - source = VirgilStreamDataSource(input_stream) - signature = signer.sign(source, private_key.raw_key) + signer = Signer() + signer.set_hash(Sha512()) + signer.reset() + + self.__for_each_chunk_input(input_stream, signer.update) + + signature = signer.sign(private_key.private_key) return signature - def verify_stream(self, input_stream, signature, signer_public_key): - # type: (io.IOBase, Union[Tuple[int], List[int]], PublicKey) -> bool + def verify_stream_signature(self, input_stream, signature, signer_public_key): + # type: (io.IOBase, Union[Tuple[int], List[int], bytearray], VirgilPublicKey) -> bool """Verifies the specified signature using original stream and signer's Public key. Args: @@ -386,28 +489,15 @@ def verify_stream(self, input_stream, signature, signer_public_key): Returns: True if signature is valid, False otherwise. """ - signer = VirgilStreamSigner(self.signature_hash_algorithm) - source = VirgilStreamDataSource(input_stream) - is_valid = signer.verify(source, signature, signer_public_key.raw_key) - return is_valid - - def calculate_fingerprint(self, data): - # type: (Union[Tuple[int], List[int]]) -> Fingerprint - """Calculates the fingerprint. - - Args: - data: data bytes for fingerprint calculation. - - Returns: - Fingerprint of the source data. - """ - hash_data = self.__calculate_hash(data) + verifier = Verifier() + verifier.reset(bytearray(signature)) - return Fingerprint(hash_data) + self.__for_each_chunk_input(input_stream, verifier.update) + return verifier.verify(signer_public_key.public_key) @staticmethod - def compute_hash(data, algorithm): - # type: (Union[Tuple[int], List[int]], int) -> Tuple[int] + def compute_hash(data, algorithm=HashAlgorithm.SHA512): + # type: (Union[Tuple[int], List[int], bytearray], int) -> Tuple[int] """Computes the hash of specified data. Args: @@ -419,41 +509,62 @@ def compute_hash(data, algorithm): Hash bytes. """ native_algorithm = HashAlgorithm.convert_to_native(algorithm) - native_hasher = VirgilHash(native_algorithm) - return native_hasher.hash(data) + native_hasher = native_algorithm() + return native_hasher.hash(bytearray(data)) - def compute_public_key_hash(self, public_key): + def compute_public_key_identifier(self, public_key): # type: (PublicKey) -> Tuple[int] - """Computes the hash of specified public key using SHA256 algorithm. + """Computes public key identifier. + + Note: Takes first 8 bytes of SHA512 of public key DER if use_sha256_fingerprints=False + and SHA256 of public key der if use_sha256_fingerprints=True Args: - public_key: public key for hashing. + public_key: public key for compute. Returns: - Hash bytes. + Public key identifier. """ - public_key_der = VirgilKeyPair.publicKeyToDER(public_key) - hash_data = self.__calculate_hash(public_key_der) - return hash_data + serializer = KeyAsn1Serializer() + serializer.setup_defaults() + + public_key_data = serializer.serialize_public_key(public_key) + + if self.use_sha256_fingerprints: + return self.compute_hash(public_key_data, HashAlgorithm.SHA256) + return self.compute_hash(public_key_data)[:8] - @property - def custom_param_key_signature(self): - # type: () -> Tuple[int] - """Custom param key signature. + def generate_random_data(self, data_size): + # type: (int) -> Tuple[int] + """Generates cryptographically secure random bytes. Uses CTR DRBG + + Args: + data_size: size needed Returns: - `VIRGIL-DATA-SIGNATURE` bytes. + Random data """ - if self._CUSTOM_PARAM_KEY_SIGNATURE: - return self._CUSTOM_PARAM_KEY_SIGNATURE - self._CUSTOM_PARAM_KEY_SIGNATURE = self.strtobytes("VIRGIL-DATA-SIGNATURE") - return self._CUSTOM_PARAM_KEY_SIGNATURE - - def __calculate_hash(self, data): - if self.use_sha256_fingerprints: - hash_algorithm = HashAlgorithm.SHA256 - calculated_hash = self.compute_hash(data, hash_algorithm) - else: - hash_algorithm = HashAlgorithm.SHA512 - calculated_hash = self.compute_hash(data, hash_algorithm)[0:8] - return calculated_hash + return self.rng.random(data_size) + + def __for_each_chunk_input(self, input_stream, stream_callback): + if input_stream.closed: + input_stream.open() + + while True: + chunk = input_stream.read(self.chunk_size) + if not chunk: + break + stream_callback(chunk) + + def __for_each_chunk_output(self, input_stream, output_stream, stream_callback): + if input_stream.closed: + input_stream.open() + + if output_stream.closed: + output_stream.open() + + while True: + chunk = input_stream.read(self.chunk_size) + if not chunk: + break + output_stream.write(stream_callback(chunk)) diff --git a/virgil_crypto/tests/hashes/__init__.py b/virgil_crypto/errors/__init__.py similarity index 89% rename from virgil_crypto/tests/hashes/__init__.py rename to virgil_crypto/errors/__init__.py index 6ca2bce..efe988e 100644 --- a/virgil_crypto/tests/hashes/__init__.py +++ b/virgil_crypto/errors/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. +# Copyright (C) 2016-2019 Virgil Security Inc. # # Lead Maintainer: Virgil Security Inc. # @@ -30,4 +30,7 @@ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +# POSSIBILITY OF SUCH DAMAGE. + +from .virgil_crypto_error import VirgilCryptoError +from .virgil_crypto_error import VirgilCryptoErrors diff --git a/virgil_crypto/streams.py b/virgil_crypto/errors/virgil_crypto_error.py similarity index 60% rename from virgil_crypto/streams.py rename to virgil_crypto/errors/virgil_crypto_error.py index d4a7933..5d90cb5 100644 --- a/virgil_crypto/streams.py +++ b/virgil_crypto/errors/virgil_crypto_error.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. +# Copyright (C) 2016-2019 Virgil Security Inc. # # Lead Maintainer: Virgil Security Inc. # @@ -32,35 +32,23 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from virgil_crypto.virgil_crypto_python import VirgilDataSink -from virgil_crypto.virgil_crypto_python import VirgilDataSource +class VirgilCryptoError(Exception): -class VirgilStreamDataSink(VirgilDataSink): - def __init__(self, stream): - super(VirgilStreamDataSink, self).__init__() - self.stream = stream + def __init__(self, message): + super(Exception, self).__init__(message) - def isGood(self): - return self.stream.writable() - def write(self, data): - self.stream.write(bytearray(data)) +class VirgilCryptoErrors(object): - -class VirgilStreamDataSource(VirgilDataSource): - def __init__(self, stream, buffer_size=1024): - super(VirgilStreamDataSource, self).__init__() - self.stream = stream - self.has_data = True - self.buffer = bytearray(buffer_size) - - def hasData(self): - return self.stream.readable() and self.has_data - - def read(self): - read_count = self.stream.readinto(self.buffer) - if not read_count: - self.has_data = False - return [] - return self.buffer[0:read_count] + SIGNER_NOT_FOUND = VirgilCryptoError("Signer not found") + SIGNATURE_NOT_FOUND = VirgilCryptoError("Signature not found") + SIGNATURE_NOT_VERIFIED = VirgilCryptoError("Signature not verified") + UNKNOWN_ALG_ID = VirgilCryptoError("Unknown alg id") + RSA_SHOULD_BE_CONSTRUCTED_DIRECTLY = VirgilCryptoError("Rsa should be constructed directly") + UNSUPPORTED_RSA_LENGTH = VirgilCryptoError("Unsupported rsa length") + KEY_DOESNT_SUPPORT_SIGNING = VirgilCryptoError("Key doesn't support signing") + PASSED_KEY_IS_NOT_VIRGIL = VirgilCryptoError("Passed key is not virgil") + OUTPUT_STREAM_ERROR = VirgilCryptoError("Output stream has no space left") + INPUT_STREAM_ERROR = VirgilCryptoError("Output stream has no space left") + INVALID_SEED_SIZE = VirgilCryptoError("Invalid seed size") diff --git a/virgil_crypto/hashes/__init__.py b/virgil_crypto/hashes/__init__.py index 0f75df8..710c51d 100644 --- a/virgil_crypto/hashes/__init__.py +++ b/virgil_crypto/hashes/__init__.py @@ -33,4 +33,3 @@ # POSSIBILITY OF SUCH DAMAGE. from .hash_algorithm import HashAlgorithm -from .fingerprint import Fingerprint diff --git a/virgil_crypto/hashes/fingerprint.py b/virgil_crypto/hashes/fingerprint.py deleted file mode 100644 index c975490..0000000 --- a/virgil_crypto/hashes/fingerprint.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import virgil_crypto - - -class Fingerprint(object): - """Fingerprint container class. - - Class provides methods for importing and exporting fingerprints. - """ - def __init__(self, fingerprint_data): - self._fingerprint_data = fingerprint_data - - @classmethod - def from_hex(cls, fingerprint_hex): - # type: (str) -> Fingerprint - """Creates new Fingerprint from hex. - - Args: - fingerprint_hex: hex string of the fingerprint. - - Returns: - Imported Fingerprint. - """ - data = virgil_crypto.VirgilByteArrayUtils.hexToBytes(fingerprint_hex) - return cls(data) - - @property - def value(self): - # type: () -> Tuple[*int] - """Raw fingerprint value. - - Returns: - Fingerprint bytes. - """ - return self._fingerprint_data - - @property - def to_hex(self): - # type: () -> str - """Fingerprint data in hexadecimal. - - Returns: - Hexademical fingerprint representation. - """ - hex_data = virgil_crypto.VirgilByteArrayUtils.bytesToHex(self.value) - return hex_data diff --git a/virgil_crypto/hashes/hash_algorithm.py b/virgil_crypto/hashes/hash_algorithm.py index 89ba537..9722611 100644 --- a/virgil_crypto/hashes/hash_algorithm.py +++ b/virgil_crypto/hashes/hash_algorithm.py @@ -31,8 +31,7 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. - -import virgil_crypto +from virgil_crypto_lib.foundation import Sha224, Sha256, Sha384, Sha512 class HashAlgorithm(object): @@ -47,25 +46,21 @@ def __init__(self, algorithm): def __str__(self): return "KeyPairType not found: %i" % self.algorithm - MD5 = 0 - SHA1 = 1 - SHA224 = 2 - SHA256 = 3 - SHA384 = 4 - SHA512 = 5 + SHA224 = 0 + SHA256 = 1 + SHA384 = 2 + SHA512 = 3 _ALGORITHMS_TO_NATIVE = { - MD5: virgil_crypto.VirgilHash.Algorithm_MD5, - SHA1: virgil_crypto.VirgilHash.Algorithm_SHA1, - SHA224: virgil_crypto.VirgilHash.Algorithm_SHA224, - SHA256: virgil_crypto.VirgilHash.Algorithm_SHA256, - SHA384: virgil_crypto.VirgilHash.Algorithm_SHA384, - SHA512: virgil_crypto.VirgilHash.Algorithm_SHA512, + SHA224: Sha224, + SHA256: Sha256, + SHA384: Sha384, + SHA512: Sha512, } @classmethod def convert_to_native(cls, algorithm): - # type: (int) -> int + # type: (int) -> Type[Union[Sha224, Sha256, Sha384, Sha512]] """Converts algorithm enum value to native value Args: diff --git a/virgil_crypto/keys/__init__.py b/virgil_crypto/keys/__init__.py index 816eef8..966ceec 100644 --- a/virgil_crypto/keys/__init__.py +++ b/virgil_crypto/keys/__init__.py @@ -32,7 +32,7 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from .key_pair import KeyPair +from .virgil_key_pair import VirgilKeyPair from .key_pair_type import KeyPairType -from .private_key import PrivateKey -from .public_key import PublicKey +from .virgil_private_key import VirgilPrivateKey +from .virgil_public_key import VirgilPublicKey diff --git a/virgil_crypto/keys/key_pair_type.py b/virgil_crypto/keys/key_pair_type.py index b665be0..74992e4 100644 --- a/virgil_crypto/keys/key_pair_type.py +++ b/virgil_crypto/keys/key_pair_type.py @@ -31,13 +31,29 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. - -import virgil_crypto +from virgil_crypto_lib.foundation import AlgId class KeyPairType(object): """Enumeration containing supported KeyPairTypes""" + class KeyType(object): + + def __init__(self, alg_id, rsa_bitlen=None): + self._alg_id = alg_id + self._rsa_bitlen = rsa_bitlen + + def __eq__(self, other): + return self.alg_id == other.alg_id and self.rsa_bitlen == other.rsa_bitlen + + @property + def alg_id(self): + return self._alg_id + + @property + def rsa_bitlen(self): + return self._rsa_bitlen + class UnknownTypeException(Exception): """Exception raised when Unknown Type passed to convertion method""" @@ -48,54 +64,8 @@ def __init__(self, key_pair_type): def __str__(self): return "KeyPairType not found: %i" % self.key_pair_type - Default = 0 - RSA_2048 = 1 - RSA_3072 = 2 - RSA_4096 = 3 - RSA_8192 = 4 - EC_SECP256R1 = 5 - EC_SECP384R1 = 6 - EC_SECP521R1 = 7 - EC_BP256R1 = 8 - EC_BP384R1 = 9 - EC_BP512R1 = 10 - EC_SECP256K1 = 11 - EC_CURVE25519 = 12 - FAST_EC_X25519 = 13 - FAST_EC_ED25519 = 14 - - _TYPES_TO_NATIVE = { - Default: virgil_crypto.VirgilKeyPair.Type_FAST_EC_ED25519, - RSA_2048: virgil_crypto.VirgilKeyPair.Type_RSA_2048, - RSA_3072: virgil_crypto.VirgilKeyPair.Type_RSA_3072, - RSA_4096: virgil_crypto.VirgilKeyPair.Type_RSA_4096, - RSA_8192: virgil_crypto.VirgilKeyPair.Type_RSA_8192, - EC_SECP256R1: virgil_crypto.VirgilKeyPair.Type_EC_SECP256R1, - EC_SECP384R1: virgil_crypto.VirgilKeyPair.Type_EC_SECP384R1, - EC_SECP521R1: virgil_crypto.VirgilKeyPair.Type_EC_SECP521R1, - EC_BP256R1: virgil_crypto.VirgilKeyPair.Type_EC_BP256R1, - EC_BP384R1: virgil_crypto.VirgilKeyPair.Type_EC_BP384R1, - EC_BP512R1: virgil_crypto.VirgilKeyPair.Type_EC_BP512R1, - EC_SECP256K1: virgil_crypto.VirgilKeyPair.Type_EC_SECP256K1, - EC_CURVE25519: virgil_crypto.VirgilKeyPair.Type_EC_CURVE25519, - FAST_EC_X25519: virgil_crypto.VirgilKeyPair.Type_FAST_EC_X25519, - FAST_EC_ED25519: virgil_crypto.VirgilKeyPair.Type_FAST_EC_ED25519, - } - - @classmethod - def convert_to_native(cls, key_pair_type): - # type: (int) -> int - """Converts type enum value to native value - - Args: - key_pair_type: type id for conversion. - - Returns: - Native library key pair type id. - - Raises: - UnknownTypeException: if type is not supported. - """ - if key_pair_type in cls._TYPES_TO_NATIVE: - return cls._TYPES_TO_NATIVE[key_pair_type] - raise cls.UnknownTypeException(key_pair_type) + CURVE25519 = KeyType(AlgId.CURVE25519) + ED25519 = KeyType(AlgId.ED25519) + RSA_2048 = KeyType(AlgId.RSA, 2048) + RSA_4096 = KeyType(AlgId.RSA, 4096) + RSA_8192 = KeyType(AlgId.RSA, 8192) diff --git a/virgil_crypto/keys/key_pair.py b/virgil_crypto/keys/virgil_key_pair.py similarity index 95% rename from virgil_crypto/keys/key_pair.py rename to virgil_crypto/keys/virgil_key_pair.py index d2b9681..45bfda8 100644 --- a/virgil_crypto/keys/key_pair.py +++ b/virgil_crypto/keys/virgil_key_pair.py @@ -34,5 +34,5 @@ from collections import namedtuple -KeyPair = namedtuple('KeyPair', ['private_key', 'public_key']) +VirgilKeyPair = namedtuple('VirgilKeyPair', ['private_key', 'public_key']) """Class containing key pair information""" diff --git a/virgil_crypto/keys/public_key.py b/virgil_crypto/keys/virgil_private_key.py similarity index 76% rename from virgil_crypto/keys/public_key.py rename to virgil_crypto/keys/virgil_private_key.py index b02f0f1..051874e 100644 --- a/virgil_crypto/keys/public_key.py +++ b/virgil_crypto/keys/virgil_private_key.py @@ -32,7 +32,16 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from collections import namedtuple -PublicKey = namedtuple('PublicKey', ['identifier', 'raw_key']) -"""Class containing public key information""" +class VirgilPrivateKey(object): + """Class containing private key information""" + + def __init__(self, identifier=None, private_key=None, key_type=None): + self.identifier = identifier + self.private_key = private_key + self.key_type = key_type + + def __eq__(self, other): + return self.identifier == other.identifier and \ + self.private_key.export_private_key() == other.private_key.export_private_key() and \ + self.key_type == other.key_type diff --git a/virgil_crypto/keys/private_key.py b/virgil_crypto/keys/virgil_public_key.py similarity index 76% rename from virgil_crypto/keys/private_key.py rename to virgil_crypto/keys/virgil_public_key.py index e6a44ab..13516e2 100644 --- a/virgil_crypto/keys/private_key.py +++ b/virgil_crypto/keys/virgil_public_key.py @@ -32,7 +32,16 @@ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from collections import namedtuple -PrivateKey = namedtuple('PrivateKey', ['identifier', 'raw_key']) -"""Class containing private key information""" +class VirgilPublicKey(object): + """Class containing public key information""" + + def __init__(self, identifier=None, public_key=None, key_type=None): + self.identifier = identifier + self.public_key = public_key + self.key_type = key_type + + def __eq__(self, other): + return self.identifier == other.identifier and \ + self.public_key.export_public_key() == other.public_key.export_public_key() and \ + self.key_type == other.key_type diff --git a/virgil_crypto/private_key_exporter.py b/virgil_crypto/private_key_exporter.py deleted file mode 100644 index bc4cc4b..0000000 --- a/virgil_crypto/private_key_exporter.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -from .crypto import VirgilCrypto - - -class PrivateKeyExporter(object): - """ - PrivateKeyExporter provides a list of methods that lets user to export and import private key. - Args: - password: The password for private key. - """ - - def __init__( - self, - password=None # type: str - ): - self.crypto = VirgilCrypto() - self.__password = password - - def export_private_key(self, private_key): - # type: (PrivateKey) -> Union[bytes, bytearray] - """ - Exports the PrivateKey into material representation. If PrivateKeyExporter was - instantiated with password then it will be used to export private key. - Args: - private_key: The private key. - Returns: - Private key in material representation of bytes. - """ - if self.__password: - return self.crypto.export_private_key(private_key, self.__password) - else: - return self.crypto.export_private_key(private_key) - - def import_private_key(self, key_data): - # type: (Union[bytes, bytearray]) -> PrivateKey - """ - Imports the private key from its material representation. If PrivateKeyExporter was - instantiated with password then it will be used to import private key. - Args: - key_data: The private key material representation bytes. - Returns: - The instance of PrivateKey imported. - """ - if self.__password: - return self.crypto.import_private_key(key_data, self.__password) - else: - return self.crypto.import_private_key(key_data) diff --git a/virgil_crypto/tests/access_token_signer_test.py b/virgil_crypto/tests/access_token_signer_test.py index 6b7d7de..c246749 100644 --- a/virgil_crypto/tests/access_token_signer_test.py +++ b/virgil_crypto/tests/access_token_signer_test.py @@ -33,6 +33,8 @@ # POSSIBILITY OF SUCH DAMAGE. import unittest +from virgil_crypto_lib.foundation._c_bridge import VirgilCryptoFoundationError + from virgil_crypto.access_token_signer import AccessTokenSigner @@ -42,7 +44,7 @@ def __init__(self, *args, **kwargs): super(AccessTokenSignerTest, self).__init__(*args, **kwargs) self.token = bytearray("test_token".encode()) self.signer = AccessTokenSigner() - key_pair = self.signer.crypto.generate_keys() + key_pair = self.signer.crypto.generate_key_pair() self.private_key = key_pair.private_key self.public_key = key_pair.public_key @@ -61,8 +63,8 @@ def test_verify_token_signature(self): def test_verify_token_signature_wrong_signature(self): signature = self.signer.generate_token_signature(self.token, self.private_key) - self.assertRaises(RuntimeError, self.signer.verify_token_signature, signature[:-2], self.token, self.public_key) - wrong_key_pair = self.signer.crypto.generate_keys() + self.assertRaises(VirgilCryptoFoundationError, self.signer.verify_token_signature, signature[:-2], self.token, self.public_key) + wrong_key_pair = self.signer.crypto.generate_key_pair() self.assertFalse(self.signer.verify_token_signature(signature, self.token, wrong_key_pair.public_key)) def test_verify_token_signature_empty_token(self): diff --git a/virgil_crypto/tests/card_crypto_test.py b/virgil_crypto/tests/card_crypto_test.py index e6848b3..876cf5f 100644 --- a/virgil_crypto/tests/card_crypto_test.py +++ b/virgil_crypto/tests/card_crypto_test.py @@ -34,7 +34,9 @@ import unittest from base64 import b64decode -from virgil_crypto.keys import PublicKey +from virgil_crypto_lib.foundation._c_bridge import VirgilCryptoFoundationError + +from virgil_crypto.keys import VirgilPublicKey from virgil_crypto.card_crypto import CardCrypto @@ -45,7 +47,7 @@ def __init__(self, *args, **kwargs): self.card_crypto = CardCrypto() self.test_text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry." self.test_data = bytearray(self.test_text.encode()) - self.key_pair = self.card_crypto.crypto.generate_keys() + self.key_pair = self.card_crypto.crypto.generate_key_pair() self.public_key = self.key_pair.public_key self.private_key = self.key_pair.private_key @@ -58,7 +60,7 @@ def test_export_public_key_empty_key(self): self.assertRaises(ValueError, self.card_crypto.export_public_key, None) def test_export_public_key_wrong_key(self): - invalid_pub_key = PublicKey(None, None) + invalid_pub_key = VirgilPublicKey(None, None, None) self.assertRaises(ValueError, self.card_crypto.export_public_key, invalid_pub_key) def test_generate_sha512(self): @@ -86,13 +88,14 @@ def test_generate_signature_wrong_key(self): def test_import_public_key(self): exported_public_key = self.card_crypto.export_public_key(self.public_key) imported_public_key = self.card_crypto.import_public_key(exported_public_key) - self.assertEqual(self.public_key, imported_public_key) + exported_after_import = self.card_crypto.export_public_key(imported_public_key) + self.assertEqual(exported_public_key, exported_after_import) def test_import_public_key_with_empty_data(self): self.assertRaises(ValueError, self.card_crypto.import_public_key, None) def test_import_public_key_with_wrong_data(self): - self.assertRaises(RuntimeError, self.card_crypto.import_public_key, self.test_data) + self.assertRaises(VirgilCryptoFoundationError, self.card_crypto.import_public_key, self.test_data) def test_verify_signature(self): test_signature = self.card_crypto.generate_signature(self.test_data, self.private_key) @@ -108,5 +111,5 @@ def test_verify_signature_with_empty_key(self): def test_verify_signature_with_invalid_signature(self): test_signature = self.card_crypto.generate_signature(self.test_data, self.private_key) self.assertRaises( - RuntimeError, self.card_crypto.verify_signature, test_signature[:-2], self.test_data, self.public_key + VirgilCryptoFoundationError, self.card_crypto.verify_signature, test_signature[:-2], self.test_data, self.public_key ) diff --git a/virgil_crypto/tests/chunk_cipher_test.py b/virgil_crypto/tests/chunk_cipher_test.py deleted file mode 100644 index 2b5e550..0000000 --- a/virgil_crypto/tests/chunk_cipher_test.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import io -import unittest - -from virgil_crypto.virgil_crypto_python import VirgilChunkCipher -from virgil_crypto.virgil_crypto_python import VirgilKeyPair -from virgil_crypto.streams import VirgilStreamDataSink -from virgil_crypto.streams import VirgilStreamDataSource - - -class VirgilChunkCipherTest(unittest.TestCase): - def test_encrypts_and_decrypts_data(self): - raw_data = bytearray("test", "utf-8") - key_pair1 = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - key_pair2 = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - cipher = VirgilChunkCipher() - cipher.addKeyRecipient(bytearray("1", "utf-8"), key_pair1.publicKey()) - cipher.addKeyRecipient(bytearray("2", "utf-8"), key_pair2.publicKey()) - encrypt_input_stream = io.BytesIO(raw_data) - encrypt_output_stream = io.BytesIO() - encrypt_source = VirgilStreamDataSource(encrypt_input_stream) - encrypt_sink = VirgilStreamDataSink(encrypt_output_stream) - cipher.encrypt(encrypt_source, encrypt_sink) - encrypted_data = encrypt_output_stream.getvalue() - decrypt_input_stream = io.BytesIO(encrypted_data) - decrypt_output_stream = io.BytesIO() - decrypt_source = VirgilStreamDataSource(decrypt_input_stream) - decrypt_sink = VirgilStreamDataSink(decrypt_output_stream) - cipher = VirgilChunkCipher() - cipher.decryptWithKey( - decrypt_source, - decrypt_sink, - bytearray("1", "utf-8"), - key_pair1.privateKey() - ) - decrypted_data1 = decrypt_output_stream.getvalue() - self.assertEqual( - raw_data, - bytearray(decrypted_data1) - ) - decrypt_input_stream = io.BytesIO(encrypted_data) - decrypt_output_stream = io.BytesIO() - decrypt_source = VirgilStreamDataSource(decrypt_input_stream) - decrypt_sink = VirgilStreamDataSink(decrypt_output_stream) - cipher.decryptWithKey( - decrypt_source, - decrypt_sink, - bytearray("2", "utf-8"), - key_pair2.privateKey() - ) - decrypted_data2 = decrypt_output_stream.getvalue() - self.assertEqual( - raw_data, - bytearray(decrypted_data2) - ) diff --git a/virgil_crypto/tests/cipher_test.py b/virgil_crypto/tests/cipher_test.py index 418463f..5d82723 100644 --- a/virgil_crypto/tests/cipher_test.py +++ b/virgil_crypto/tests/cipher_test.py @@ -34,34 +34,59 @@ import unittest -from virgil_crypto.virgil_crypto_python import VirgilCipher -from virgil_crypto.virgil_crypto_python import VirgilKeyPair +from virgil_crypto_lib.foundation import RecipientCipher, Aes256Gcm, CtrDrbg + +from virgil_crypto import VirgilCrypto +from virgil_crypto.keys import KeyPairType class VirgilCipherTest(unittest.TestCase): def test_encrypts_and_decrypts_data(self): raw_data = bytearray("test", "utf-8") - key_pair1 = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - key_pair2 = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - cipher = VirgilCipher() - cipher.addKeyRecipient(bytearray("1", "utf-8"), key_pair1.publicKey()) - cipher.addKeyRecipient(bytearray("2", "utf-8"), key_pair2.publicKey()) - encrypted_data = cipher.encrypt(raw_data) - cipher = VirgilCipher() - decrypted_data1 = cipher.decryptWithKey( - encrypted_data, + + rng = CtrDrbg() + rng.setup_defaults() + + key_pair1 = VirgilCrypto().generate_key_pair(KeyPairType.ED25519) + key_pair2 = VirgilCrypto().generate_key_pair(KeyPairType.ED25519) + + cipher = RecipientCipher() + aes_gcm = Aes256Gcm() + + cipher.set_encryption_cipher(aes_gcm) + cipher.set_random(rng) + + cipher.add_key_recipient(bytearray("1", "utf-8"), key_pair1.public_key.public_key) + cipher.add_key_recipient(bytearray("2", "utf-8"), key_pair2.public_key.public_key) + + cipher.start_encryption() + encrypted_data = cipher.pack_message_info() + encrypted_data += cipher.process_encryption(raw_data) + encrypted_data += cipher.finish_encryption() + + cipher.start_decryption_with_key( bytearray("1", "utf-8"), - key_pair1.privateKey() + key_pair1.private_key.private_key, + bytearray() ) + decrypted_data1 = bytearray() + decrypted_data1 += cipher.process_decryption(encrypted_data) + decrypted_data1 += cipher.finish_decryption() + self.assertEqual( raw_data, bytearray(decrypted_data1) ) - decrypted_data2 = cipher.decryptWithKey( - encrypted_data, + + cipher.start_decryption_with_key( bytearray("2", "utf-8"), - key_pair2.privateKey() + key_pair2.private_key.private_key, + bytearray() ) + decrypted_data2 = bytearray() + decrypted_data2 += cipher.process_decryption(encrypted_data) + decrypted_data2 += cipher.finish_decryption() + self.assertEqual( raw_data, bytearray(decrypted_data2) diff --git a/virgil_crypto/tests/compatibility_test.py b/virgil_crypto/tests/compatibility_test.py index 2549c30..796ec19 100644 --- a/virgil_crypto/tests/compatibility_test.py +++ b/virgil_crypto/tests/compatibility_test.py @@ -42,7 +42,7 @@ try: basestring except NameError: - basestring=str + basestring = str class CompatibilityTest(unittest.TestCase): @@ -55,34 +55,36 @@ def __init__(self, *args, **kwargs): def test_encrypt_single_recipient(self): self._crypto.use_sha256_fingerprints = True data = self._compatibility_data["encrypt_single_recipient"] - private_key = self._crypto.import_private_key(data["private_key"]) + private_key = self._crypto.import_private_key(data["private_key"]).private_key decrypted_data = self._crypto.decrypt(data["cipher_data"], private_key) - self.assertEqual(data["original_data"], decrypted_data) + self.assertEqual(bytearray(data["original_data"]), bytearray(decrypted_data)) def test_encrypt_multiple_recipients(self): self._crypto.use_sha256_fingerprints = True data = self._compatibility_data["encrypt_multiple_recipients"] - private_keys = [self._crypto.import_private_key(pk) for pk in data["private_keys"]] + private_keys = [self._crypto.import_private_key(pk).private_key for pk in data["private_keys"]] + self.assertGreater(len(private_keys), 0) for private_key in private_keys: decrypted_data = self._crypto.decrypt(data["cipher_data"], private_key) - self.assertEqual(data["original_data"], decrypted_data) + self.assertEqual(bytearray(data["original_data"]), bytearray(decrypted_data)) def test_sign_then_encrypt_single_recipient(self): self._crypto.use_sha256_fingerprints = True data = self._compatibility_data["sign_then_encrypt_single_recipient"] - private_key = self._crypto.import_private_key(data["private_key"]) + private_key = self._crypto.import_private_key(data["private_key"]).private_key public_key = self._crypto.extract_public_key(private_key) decrypted_data = self._crypto.decrypt_then_verify( data["cipher_data"], private_key, public_key ) - self.assertEqual(data["original_data"], decrypted_data) + self.assertEqual(bytearray(data["original_data"]), bytearray(decrypted_data)) def test_sign_then_encrypt_multiple_recipients(self): self._crypto.use_sha256_fingerprints = True data = self._compatibility_data["sign_then_encrypt_multiple_recipients"] - private_keys = [self._crypto.import_private_key(pk) for pk in data["private_keys"]] + private_keys = [self._crypto.import_private_key(pk).private_key for pk in data["private_keys"]] + self.assertGreater(len(private_keys), 0) public_key = self._crypto.extract_public_key(private_keys[0]) for private_key in private_keys: decrypted_data = self._crypto.decrypt_then_verify( @@ -90,20 +92,40 @@ def test_sign_then_encrypt_multiple_recipients(self): private_key, public_key ) - self.assertEqual(data["original_data"], decrypted_data) + self.assertEqual(bytearray(data["original_data"]), bytearray(decrypted_data)) def test_generate_signature(self): data = self._compatibility_data["generate_signature"] - private_key = self._crypto.import_private_key(data["private_key"]) - signature = self._crypto.sign(data["original_data"], private_key) + private_key = self._crypto.import_private_key(data["private_key"]).private_key + signature = self._crypto.generate_signature(data["original_data"], private_key) public_key = self._crypto.extract_public_key(private_key) self.assertTrue( - self._crypto.verify(data["original_data"], data["signature"], public_key) + self._crypto.verify_signature(data["original_data"], data["signature"], public_key) ) self.assertTrue( - self._crypto.verify(data["original_data"], signature, public_key) + self._crypto.verify_signature(data["original_data"], signature, public_key) ) + def test_decrypt_then_verify_multiple_signers(self): + self._crypto.use_sha256_fingerprints = True + data = self._compatibility_data["sign_then_encrypt_multiple_signers"] + private_key = self._crypto.import_private_key(data["private_key"]).private_key + public_keys = [self._crypto.import_public_key(pk) for pk in data["public_keys"]] + decrypted_data = self._crypto.decrypt_then_verify( + data["cipher_data"], + private_key, + public_keys + ) + self.assertEqual(bytearray(data["original_data"]), bytearray(decrypted_data)) + + def generate_ed25519_using_seed(self): + data = self._compatibility_data["generate_ed25519_using_seed"] + seed = base64.b64decode(data["seed"]) + key_pair = self._crypto.generate_key_pair(seed=seed) + self.assertEqual(base64.b64decode(data["private_key"]), self._crypto.export_private_key(key_pair.private_key)) + self.assertEqual(base64.b64decode(data["pubblic_key"]), self._crypto.export_public_key(key_pair.public_key)) + + @property def _crypto(self): if self.__crypto: diff --git a/virgil_crypto/tests/crypto_test.py b/virgil_crypto/tests/crypto_test.py index 060cade..93ddd8d 100644 --- a/virgil_crypto/tests/crypto_test.py +++ b/virgil_crypto/tests/crypto_test.py @@ -36,8 +36,10 @@ import unittest from base64 import b64decode -from virgil_crypto import crypto, VirgilKeyPair +from virgil_crypto_lib.foundation._c_bridge import VirgilCryptoFoundationError + from virgil_crypto import VirgilCrypto +from virgil_crypto.errors import VirgilCryptoError from virgil_crypto.hashes import HashAlgorithm @@ -49,64 +51,40 @@ def test_strtobytes(self): self.assertEqual(self._crypto().strtobytes('test'), (116, 101, 115, 116)) def test_import_private_key(self): - key_pair = self._crypto().generate_keys() - private_key_data = key_pair.private_key.raw_key - self.assertEqual( - self._crypto().import_private_key(private_key_data), - key_pair.private_key - ) - - def test_import_public_key(self): - key_pair = self._crypto().generate_keys() - public_key_data = key_pair.public_key.raw_key + key_pair = self._crypto().generate_key_pair() + private_key_data = self._crypto().export_private_key(key_pair.private_key) + imported_key_pair = self._crypto().import_private_key(private_key_data) self.assertEqual( - self._crypto().import_public_key(public_key_data), - key_pair.public_key + key_pair.private_key.identifier, + imported_key_pair.private_key.identifier, ) - def test_export_and_import_private_key_with_password(self): - password = '123456' - key_pair = self._crypto().generate_keys() - exported_private_key = self._crypto().export_private_key( - key_pair.private_key, - password - ) - self.assertNotEqual( - exported_private_key, - key_pair.private_key.raw_key - ) - imported_private_key = self._crypto().import_private_key( - exported_private_key, - password - ) - self.assertEqual( - imported_private_key, - key_pair.private_key - ) - - def test_export_public_key(self): - key_pair = self._crypto().generate_keys() + def test_import_export_public_key(self): + key_pair = self._crypto().generate_key_pair() exported_public_key = self._crypto().export_public_key( key_pair.public_key ) + imported_public_key = self._crypto().import_public_key( + exported_public_key + ) self.assertEqual( - exported_public_key, - key_pair.public_key.raw_key + key_pair.public_key.identifier, + imported_public_key.identifier ) def test_extract_public_key(self): - key_pair = self._crypto().generate_keys() + key_pair = self._crypto().generate_key_pair() extracted_public_key = self._crypto().extract_public_key( key_pair.private_key, ) self.assertEqual( - extracted_public_key, - key_pair.public_key + key_pair.public_key.identifier, + extracted_public_key.identifier ) def test_encrypt_and_decrypt_values(self): data = [1, 2, 3] - key_pair = self._crypto().generate_keys() + key_pair = self._crypto().generate_key_pair() encrypt_result = self._crypto().encrypt( data, key_pair.public_key @@ -121,53 +99,73 @@ def test_encrypt_and_decrypt_values(self): ) def test_encrypt_and_decrypt_stream(self): - data = bytearray([1, 2, 3]) - key_pair = self._crypto().generate_keys() + data = bytearray([2, 3, 4]) + key_pair_1 = self._crypto().generate_key_pair() + key_pair_2 = self._crypto().generate_key_pair() + encrypt_input_stream = io.BytesIO(data) encrypt_output_stream = io.BytesIO() self._crypto().encrypt_stream( encrypt_input_stream, encrypt_output_stream, - key_pair.public_key + key_pair_1.public_key ) - encrypt_stream_result = encrypt_output_stream.getvalue() - decrypt_input_stream = io.BytesIO(encrypt_stream_result) + encrypt_stream_data = encrypt_output_stream.getvalue() + + decrypt_input_stream = io.BytesIO(encrypt_stream_data) decrypt_output_stream = io.BytesIO() self._crypto().decrypt_stream( decrypt_input_stream, decrypt_output_stream, - key_pair.private_key + key_pair_1.private_key ) - decrypt_stream_result = decrypt_output_stream.getvalue() + decrypt_stream_data = decrypt_output_stream.getvalue() self.assertEqual( data, - decrypt_stream_result + decrypt_stream_data + ) + + decrypt_input_stream_2 = io.BytesIO(encrypt_stream_data) + decrypt_output_stream_2 = io.BytesIO() + self.assertRaises( + VirgilCryptoFoundationError, + self._crypto().decrypt_stream, + decrypt_input_stream_2, + decrypt_output_stream_2, + key_pair_2.private_key ) def test_sign_and_verify_values(self): data = [1, 2, 3] - key_pair = self._crypto().generate_keys() - signature = self._crypto().sign( + key_pair_1 = self._crypto().generate_key_pair() + key_pair_2 = self._crypto().generate_key_pair() + signature = self._crypto().generate_signature( data, - key_pair.private_key + key_pair_1.private_key ) - verified = self._crypto().verify( + verified = self._crypto().verify_signature( data, signature, - key_pair.public_key + key_pair_1.public_key + ) + not_verified = self._crypto().verify_signature( + data, + signature, + key_pair_2.public_key ) self.assertTrue(verified) + self.assertFalse(not_verified) def test_sign_and_verify_values_sha265(self): data = [1, 2, 3] cr = self._crypto() cr.signature_hash_algorithm = HashAlgorithm.SHA256 - key_pair = cr.generate_keys() - signature = cr.sign( + key_pair = cr.generate_key_pair() + signature = cr.generate_signature( data, key_pair.private_key ) - verified = cr.verify( + verified = cr.verify_signature( data, signature, key_pair.public_key @@ -176,14 +174,14 @@ def test_sign_and_verify_values_sha265(self): def test_sign_and_verify_stream(self): data = bytearray([1, 2, 3]) - key_pair = self._crypto().generate_keys() + key_pair = self._crypto().generate_key_pair() sign_input_stream = io.BytesIO(data) - signature = self._crypto().sign_stream( + signature = self._crypto().generate_stream_signature( sign_input_stream, key_pair.private_key ) verify_input_stream = io.BytesIO(data) - verified = self._crypto().verify_stream( + verified = self._crypto().verify_stream_signature( verify_input_stream, signature, key_pair.public_key @@ -194,30 +192,24 @@ def test_sign_and_verify_stream_sha256(self): data = bytearray([1, 2, 3]) cr = self._crypto() cr.signature_hash_algorithm = HashAlgorithm.SHA256 - key_pair = cr.generate_keys() + key_pair = cr.generate_key_pair() sign_input_stream = io.BytesIO(data) - signature = cr.sign_stream( + signature = cr.generate_stream_signature( sign_input_stream, key_pair.private_key ) verify_input_stream = io.BytesIO(data) - verified = cr.verify_stream( + verified = cr.verify_stream_signature( verify_input_stream, signature, key_pair.public_key ) self.assertTrue(verified) - def test_calculate_fingerprint(self): - data = bytearray([1, 2, 3]) - fingerprint = self._crypto().calculate_fingerprint(data) - self.assertTrue(fingerprint.value) - self.assertIsInstance(fingerprint, crypto.Fingerprint) - def test_private_key_identifier_is_correct(self): # STC-33 crypto_1 = VirgilCrypto() - key_pair_1 = crypto_1.generate_keys() + key_pair_1 = crypto_1.generate_key_pair() self.assertEqual( hashlib.sha512(bytearray(crypto_1.export_public_key(key_pair_1.public_key))).digest()[0:8], @@ -226,7 +218,7 @@ def test_private_key_identifier_is_correct(self): crypto_2 = VirgilCrypto() crypto_2.use_sha256_fingerprints = True - key_pair_2 = crypto_2.generate_keys() + key_pair_2 = crypto_2.generate_key_pair() self.assertEqual( hashlib.sha256(bytearray(crypto_2.export_public_key(key_pair_2.public_key))).digest(), @@ -236,7 +228,7 @@ def test_private_key_identifier_is_correct(self): def test_public_key_identifier_is_correct(self): # STC-33 crypto_1 = VirgilCrypto() - key_pair_1 = crypto_1.generate_keys() + key_pair_1 = crypto_1.generate_key_pair() public_key_1 = crypto_1.extract_public_key(key_pair_1.private_key) self.assertEqual(public_key_1.identifier, key_pair_1.public_key.identifier) self.assertEqual(crypto_1.export_public_key(public_key_1), crypto_1.export_public_key(key_pair_1.public_key)) @@ -247,7 +239,7 @@ def test_public_key_identifier_is_correct(self): crypto_2 = VirgilCrypto() crypto_2.use_sha256_fingerprints = True - key_pair_2 = crypto_2.generate_keys() + key_pair_2 = crypto_2.generate_key_pair() public_key_2 = crypto_2.extract_public_key(key_pair_2.private_key) self.assertEqual(public_key_2.identifier, key_pair_2.public_key.identifier) self.assertEqual(crypto_1.export_public_key(public_key_2), crypto_1.export_public_key(key_pair_2.public_key)) @@ -256,41 +248,39 @@ def test_public_key_identifier_is_correct(self): bytearray(key_pair_2.public_key.identifier) ) - def test_private_key_is_der(self): - # STC-31 - crypto = VirgilCrypto() - key_pair_1 = crypto.generate_keys() - private_key_data_1 = crypto.export_private_key(key_pair_1.private_key) - self.assertEqual(VirgilKeyPair.privateKeyToDER(private_key_data_1), private_key_data_1) - - private_key_2_bytes = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUg4bnIyV05nblkya1ZScjRValp4UnJWVGpiMW4wWGdBZkhOWE1ocVkwaVAKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=" - private_key_2 = crypto.import_private_key(bytearray(b64decode(private_key_2_bytes))) - private_key_2 = key_pair_1.private_key - private_key_2_data = crypto.export_private_key(private_key_2) - self.assertEqual(VirgilKeyPair.privateKeyToDER(private_key_2_data), private_key_2_data) - - private_key_3_bytes = "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLQpNSUdoTUYwR0NTcUdTSWIzRFFFRkRUQlFNQzhHQ1NxR1NJYjNEUUVGRERBaUJCQ3kzSkk3V0VDcGVHZGFIdEc2CktHcjRBZ0lkWXpBS0JnZ3Foa2lHOXcwQ0NqQWRCZ2xnaGtnQlpRTUVBU29FRUp1Wlpqb0oyZGJGdUpZN0ZNSisKN3g0RVFEcnRpZjNNb29rQk5PRTBUaGZmSEtrV0R3K3lvZ0ZRRk1RRFJtU0kwSXl2T2w4RTVnck5QcFNxU3dQNApIL2lzYzJvQVJzSW03alVRQXkrQjl5aTRZK3c9Ci0tLS0tRU5EIEVOQ1JZUFRFRCBQUklWQVRFIEtFWS0tLS0tCg==" - private_key_3 = crypto.import_private_key(bytearray(b64decode(private_key_3_bytes)), password="qwerty") - private_key_3_data = crypto.export_private_key(private_key_3) - self.assertEqual(VirgilKeyPair.privateKeyToDER(private_key_3_data), private_key_3_data) - - def test_public_key_is_der(self): - # STC-32 - crypto = VirgilCrypto() - key_pair_1 = crypto.generate_keys() - public_key_data_1 = crypto.export_public_key(key_pair_1.public_key) - self.assertEqual(VirgilKeyPair.publicKeyToDER(public_key_data_1), public_key_data_1) - - public_key_bytes = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQXYycWRHa0w2RmRxc0xpLzdPQTA1NjJPOVYvVDhFN3F6RmF0RjZMcW9TY3M9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=" - public_key_2 = crypto.import_public_key(bytearray(b64decode(public_key_bytes))) - public_key_data_2 = crypto.export_public_key(public_key_2) - self.assertEqual(VirgilKeyPair.publicKeyToDER(public_key_data_2), public_key_data_2) - def test_signature_hash(self): # STC-30 crypto = VirgilCrypto() - key_pair = crypto.generate_keys() + key_pair = crypto.generate_key_pair() test_data = bytearray("test".encode()) - signature = crypto.sign(test_data, key_pair.private_key) + signature = crypto.generate_signature(test_data, key_pair.private_key) self.assertEqual(bytearray(signature[0:17]), b64decode("MFEwDQYJYIZIAWUDBAIDBQA=")) + + def test_sign_then_encrypt(self): + crypto = VirgilCrypto() + key_pair_1 = crypto.generate_key_pair() + key_pair_2 = crypto.generate_key_pair() + key_pair_3 = crypto.generate_key_pair() + data = [1, 2, 3] + + cipher_data = crypto.sign_then_encrypt(data, key_pair_1.private_key, key_pair_2.public_key) + + decrypted_data = crypto.decrypt_then_verify(cipher_data, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + + self.assertEqual(data, list(decrypted_data)) + + self.assertRaises(VirgilCryptoError, crypto.decrypt_then_verify, cipher_data, key_pair_2.private_key, key_pair_3.public_key) + + def test_generate_key_using_seed(self): + crypto = VirgilCrypto() + seed = crypto.generate_random_data(32) + + key_id = crypto.generate_key_pair(seed=seed).private_key.identifier + + retries = 5 + while retries > 0: + key_pair = crypto.generate_key_pair(seed=seed) + self.assertTrue(key_id, key_pair.private_key.identifier) + self.assertTrue(key_pair.private_key.identifier, key_pair.public_key.identifier) + retries -= 1 diff --git a/virgil_crypto/tests/data/sdk_compatibility_data.json b/virgil_crypto/tests/data/sdk_compatibility_data.json index d5c8e2d..2b52e1b 100644 --- a/virgil_crypto/tests/data/sdk_compatibility_data.json +++ b/virgil_crypto/tests/data/sdk_compatibility_data.json @@ -50,5 +50,10 @@ ], "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgV+lgOdbbR8aHUjIEx/YblRLUe/bGcH48E86p0I45JkMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCAIRQh5ho70Jl3wuIpZxMv7bRzWgZDoBFtZafbiXCp2jAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMNPkFuMoCS/A9nzgZQ5lie5laQnGcfPYZVm6iwxual6USPOF6oqZd0EJu2xKx188IzBRMB0GCWCGSAFlAwQBKgQQd1cWGby4gwQgB8MTRmQxwgQweMtdoScv4IEQu0jwTXgasA3LvgUOiIAeSvUSdiYlh55Vx6sTe7cXjoheLKclSWgLMIIBFQIBAqAiBCB06AofjB8oEBQU0dRxXdJsbOSUq7Xscawaz29Akghv+DAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC8xBHqoj3SJ3lnrZRi4sKrLpAEv53VuyFeyyZr5parBMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwd/+fkUJ92w1AxbBGEtOZUQXVKplYlbfgZVxTdwPFEFaVxHkRf2DFLjYcA8eJxl+mMFEwHQYJYIZIAWUDBAEqBBB2sx1N39H6gkHGSSDxSWM+BDDQXM5d9avTHrLEzOOwWe3vtpFxkefz0/8T06c3UMxvhMp/TM3xYXgSQ1dDrDuMAVowggEVAgECoCIEIK8P8zsSxEpPs/6UDFfKP3/pz/Gas6c1VMnv7xUOhQVbMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXjeOtEDF+FzRvyGoKlUwfuC+cbGonXmQ1lfbvClLHYMwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDBSEicWwBP9gcdwbi3TlsX3YMWs3ue18iUUltu05uFruh+c2xYwTwo2Zt+oPNHT+mYwUTAdBglghkgBZQMEASoEEJaLW/UPxiYD1z4RQh0qMxMEMKVsy7VquNAYLvuaFdYJszzz5HtqlC9OnCiEOc9gecKL8KQ3bU0l4vL4pFl7SgBCJzCCARUCAQKgIgQgz3bkz4SRK/ndLceAz5A1rc4QpUdQsOKSg8Lpg9Yd29swBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCjOgxFr+VCWdngH0SQMu6bfcUFqWooDGDut0G0t7RSEzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMKADb3wAPzdJ+BsuKBB59pdL3HpV/hCRGtZtzHqfiIdTFsv+kMczigySgKGvysJrKzBRMB0GCWCGSAFlAwQBKgQQ/uq+33Aivg92/9lpF8feHQQwILYYaJz55qTzFwLe21a+oo9av0A/7mNBkqW4ogGn4/fOJ4T2Pwlt8kZor033rBHkMIIBFQIBAqAiBCDX7SnuiYY1nMfPaqFGbEssf4GXA3LlB97QLjJ+CjlazjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAHnBZCXOZ365uuylYUJcsG91xVq46zmnAKkDRI3uOAATMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwM/lDhsv7B0Qq45Zi9pP7oKrlhzhtYlNk8Wh1uKA9mBWLqVQ61NlQVm9F2gk1gpPsMFEwHQYJYIZIAWUDBAEqBBDBBGvJ5lNVVw9/2/JU9ZHSBDA8y9XblGHB40qIniw+TeAt87peZP/mCYd4NCk91wt3perCNMhEJhoBq3KnB91Lyq4wJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMXnmCLfBKuPnH+nxmoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCDPduTPhJEr+d0tx4DPkDWtzhClR1Cw4pKDwumD1h3b2zBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQMbcL2CbQYHafMsmut9uyZ1c4cJGWk2cQZDZ8xcb/4EXeo/cJxFDhc59TVtjIImy8L4xpVLuI6+wGfwGIPmZKwlJubsUEUn+KHvHlS4z41YCsDrxXaDN8luv5jj+ERJg9MVrHttjMTOX0IIVoxcylbi6V2wd7/+KiL0JKx3dV5syJ4by+Y0y6eY=" + }, + "generate_ed25519_using_seed": { + "seed": "Z7EcVC3lerIpP/NDZc/JeCC8RyJrJaRv313dF1KoCAQ=", + "private_key": "MC4CAQAwBQYDK2VwBCIEIFc3J0OL+8hfM5CpVlbfXLYV/nF4Yyw2SHME5MGOZ3JL", + "public_key": "MCowBQYDK2VwAyEAfzY+wOf4C2qZWNgX/ifC1YDbMqZTNaSFudB0lQHPH0c=" } } diff --git a/virgil_crypto/tests/hashes/fingerprint_test.py b/virgil_crypto/tests/hashes/fingerprint_test.py deleted file mode 100644 index d703bec..0000000 --- a/virgil_crypto/tests/hashes/fingerprint_test.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import unittest - -from virgil_crypto import VirgilCrypto -from virgil_crypto.hashes import Fingerprint - - -class FingerptintTest(unittest.TestCase): - @property - def _crypto(self): - return VirgilCrypto() - - def test_from_to_hex(self): - data = bytearray([1, 2, 3]) - fingerprint = self._crypto.calculate_fingerprint(data) - hex_string = fingerprint.to_hex - rebuilt_fingerprint = Fingerprint.from_hex(hex_string) - self.assertEqual( - fingerprint.value, - rebuilt_fingerprint.value - ) - diff --git a/virgil_crypto/tests/private_key_exporter_test.py b/virgil_crypto/tests/private_key_exporter_test.py deleted file mode 100644 index 79999ef..0000000 --- a/virgil_crypto/tests/private_key_exporter_test.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -import unittest - -from virgil_crypto import VirgilCrypto -from virgil_crypto.private_key_exporter import PrivateKeyExporter - - -class PrivateKeyExporterTest(unittest.TestCase): - - def test_export_private_key_with_password(self): - crypto = VirgilCrypto() - key_pair = crypto.generate_keys() - passwd = "test" - pke = PrivateKeyExporter(passwd) - exported_key_data = pke.export_private_key(key_pair.private_key) - self.assertIsNotNone(exported_key_data) - self.assertEqual(crypto.import_private_key(exported_key_data, passwd), key_pair.private_key) - - def test_import_private_key_with_password(self): - crypto = VirgilCrypto() - key_pair = crypto.generate_keys() - passwd = "test" - pke = PrivateKeyExporter(passwd) - exported_key_data = pke.export_private_key(key_pair.private_key) - imported_key = pke.import_private_key(exported_key_data) - self.assertIsNotNone(imported_key) - self.assertEqual(imported_key, key_pair.private_key) - - def test_export_private_key(self): - crypto = VirgilCrypto() - key_pair = crypto.generate_keys() - pke = PrivateKeyExporter() - exported_key_data = pke.export_private_key(key_pair.private_key) - self.assertIsNotNone(exported_key_data) - self.assertEqual(crypto.export_private_key(key_pair.private_key), exported_key_data) - - def test_import_private_key(self): - crypto = VirgilCrypto() - key_pair = crypto.generate_keys() - pke = PrivateKeyExporter() - exported_key_data = pke.export_private_key(key_pair.private_key) - imported_key = pke.import_private_key(exported_key_data) - self.assertIsNotNone(imported_key) - self.assertEqual(imported_key, key_pair.private_key) diff --git a/virgil_crypto/tests/signer_test.py b/virgil_crypto/tests/signer_test.py index 4f469b3..bed6c0e 100644 --- a/virgil_crypto/tests/signer_test.py +++ b/virgil_crypto/tests/signer_test.py @@ -34,15 +34,25 @@ import unittest -from virgil_crypto.virgil_crypto_python import VirgilKeyPair -from virgil_crypto.virgil_crypto_python import VirgilSigner +from virgil_crypto_lib.foundation import Verifier, Signer, Sha512 + +from virgil_crypto import VirgilCrypto +from virgil_crypto.keys import KeyPairType + class VirgilSignerTest(unittest.TestCase): + def test_signs_and_verifies_data(self): raw_data = bytearray("test", "utf-8") - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - signer = VirgilSigner() - signature = signer.sign(raw_data, key_pair.privateKey()) - signer = VirgilSigner() - is_valid = signer.verify(raw_data, signature, key_pair.publicKey()) + key_pair = VirgilCrypto().generate_key_pair(KeyPairType.ED25519) + signer = Signer() + signer.set_hash(Sha512()) + signer.reset() + signer.update(raw_data) + signature = signer.sign(key_pair.private_key.private_key) + + verifier = Verifier() + verifier.reset(signature) + verifier.update(raw_data) + is_valid = verifier.verify(key_pair.public_key.public_key) self.assertTrue(is_valid) diff --git a/virgil_crypto/tests/stream_signer_test.py b/virgil_crypto/tests/stream_signer_test.py index 8cabc00..ac899df 100644 --- a/virgil_crypto/tests/stream_signer_test.py +++ b/virgil_crypto/tests/stream_signer_test.py @@ -35,21 +35,27 @@ import io import unittest -from virgil_crypto.virgil_crypto_python import VirgilKeyPair -from virgil_crypto.virgil_crypto_python import VirgilStreamSigner -from virgil_crypto.streams import VirgilStreamDataSource +from virgil_crypto_lib.foundation import Signer, Sha512, Verifier + +from virgil_crypto import VirgilCrypto +from virgil_crypto.keys import KeyPairType class VirgilStreamSignerTest(unittest.TestCase): + def test_signs_and_verifies_data(self): raw_data = bytearray("test", "utf-8") - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) + key_pair = VirgilCrypto().generate_key_pair(KeyPairType.ED25519) input_stream = io.BytesIO(raw_data) - source = VirgilStreamDataSource(input_stream) - signer = VirgilStreamSigner() - signature = signer.sign(source, key_pair.privateKey()) + signer = Signer() + signer.set_hash(Sha512()) + signer.reset() + VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, signer.update) + signature = signer.sign(key_pair.private_key.private_key) + input_stream = io.BytesIO(raw_data) - source = VirgilStreamDataSource(input_stream) - signer = VirgilStreamSigner() - is_valid = signer.verify(source, signature, key_pair.publicKey()) + verifier = Verifier() + verifier.reset(signature) + VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, verifier.update) + is_valid = verifier.verify(key_pair.public_key.public_key) self.assertTrue(is_valid) diff --git a/virgil_crypto/tests/virgil_key_pair_test.py b/virgil_crypto/tests/virgil_key_pair_test.py deleted file mode 100644 index dc4124e..0000000 --- a/virgil_crypto/tests/virgil_key_pair_test.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (C) 2016-2018 Virgil Security Inc. -# -# Lead Maintainer: Virgil Security Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# (3) Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -import unittest - -from virgil_crypto.virgil_crypto_python import VirgilKeyPair - - -class VirgilKeyPairTest(unittest.TestCase): - def test_generates_keys(self): - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - self.assertTrue( - key_pair.publicKey() - ) - self.assertTrue( - key_pair.privateKey() - ) - - def test_converts_keys_to_der(self): - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - self.assertTrue( - VirgilKeyPair.publicKeyToDER(key_pair.publicKey()) - ) - self.assertTrue( - VirgilKeyPair.privateKeyToDER(key_pair.privateKey()) - ) - - def test_encrypts_and_decrypts_private_key(self): - password = bytearray("test", "utf-8") - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - encrypted_private_key = VirgilKeyPair.encryptPrivateKey( - key_pair.privateKey(), - password - ) - decrypted_private_key = VirgilKeyPair.decryptPrivateKey( - encrypted_private_key, - password - ) - self.assertEqual( - key_pair.privateKey(), - decrypted_private_key - ) - - def test_extracts_public_key(self): - key_pair = VirgilKeyPair.generate(VirgilKeyPair.Type_FAST_EC_ED25519) - extracted_public_key = VirgilKeyPair.extractPublicKey( - key_pair.privateKey(), - [] - ) - self.assertEqual( - key_pair.publicKey(), - extracted_public_key - ) From 68dd1025b2bd289efd2ed2cc3b3ca09cafabe728 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Mon, 10 Jun 2019 12:44:23 +0300 Subject: [PATCH 02/11] Fixed getting type for RSA keys Added tests for various types of keys --- virgil_crypto/crypto.py | 4 +- virgil_crypto/keys/key_pair_type.py | 1 + virgil_crypto/tests/crypto_formats_test.py | 71 ++++++++ virgil_crypto/tests/crypto_test.py | 178 +++++++++++++++++++++ 4 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 virgil_crypto/tests/crypto_formats_test.py diff --git a/virgil_crypto/crypto.py b/virgil_crypto/crypto.py index 6ec2092..76af680 100644 --- a/virgil_crypto/crypto.py +++ b/virgil_crypto/crypto.py @@ -141,7 +141,7 @@ def import_private_key(self, key_data): private_key = key_provider.import_private_key(bytearray(key_data)) if private_key.alg_id() == AlgId.RSA: - key_type = KeyPairType.KeyType(private_key.alg_id(), private_key.bit_length()) + key_type = KeyPairType.KeyType(private_key.alg_id(), private_key.key_bitlen()) else: key_type = KeyPairType.KeyType(private_key.alg_id()) @@ -173,7 +173,7 @@ def import_public_key(self, key_data): public_key = key_provider.import_public_key(bytearray(key_data)) if public_key.alg_id() == AlgId.RSA: - key_type = KeyPairType.KeyType(public_key.alg_id(), public_key.bit_length()) + key_type = KeyPairType.KeyType(public_key.alg_id(), public_key.key_bitlen()) else: key_type = KeyPairType.KeyType(public_key.alg_id()) diff --git a/virgil_crypto/keys/key_pair_type.py b/virgil_crypto/keys/key_pair_type.py index 74992e4..d26f2f6 100644 --- a/virgil_crypto/keys/key_pair_type.py +++ b/virgil_crypto/keys/key_pair_type.py @@ -66,6 +66,7 @@ def __str__(self): CURVE25519 = KeyType(AlgId.CURVE25519) ED25519 = KeyType(AlgId.ED25519) + SECP256R1 = KeyType(AlgId.SECP256R1) RSA_2048 = KeyType(AlgId.RSA, 2048) RSA_4096 = KeyType(AlgId.RSA, 4096) RSA_8192 = KeyType(AlgId.RSA, 8192) diff --git a/virgil_crypto/tests/crypto_formats_test.py b/virgil_crypto/tests/crypto_formats_test.py new file mode 100644 index 0000000..7d35092 --- /dev/null +++ b/virgil_crypto/tests/crypto_formats_test.py @@ -0,0 +1,71 @@ +# Copyright (C) 2016-2018 Virgil Security Inc. +# +# Lead Maintainer: Virgil Security Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# (3) Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +import unittest +from base64 import b64decode + +from virgil_crypto import VirgilCrypto +from virgil_crypto.hashes import HashAlgorithm + + +class CryptoFormatsTest(unittest.TestCase): + + def test_signature_hash(self): + data = bytearray("test".encode()) + crypto = VirgilCrypto() + key_pair = crypto.generate_key_pair() + signature = crypto.generate_signature(data, key_pair.private_key) + + self.assertEqual( + signature[:17], + bytearray(b64decode("MFEwDQYJYIZIAWUDBAIDBQA=")) + ) + + def test_key_identifier_is_correct(self): + crypto_1 = VirgilCrypto() + key_pair_1 = crypto_1.generate_key_pair() + + self.assertEqual(key_pair_1.private_key.identifier, key_pair_1.public_key.identifier) + self.assertEqual( + crypto_1.compute_hash(crypto_1.export_public_key(key_pair_1.public_key), HashAlgorithm.SHA512)[:8], + key_pair_1.private_key.identifier + ) + + crypto_2 = VirgilCrypto(use_sha256_fingerprints=True) + key_pair_2 = crypto_2.generate_key_pair() + + self.assertEqual( + crypto_2.compute_hash(crypto_1.export_public_key(key_pair_2.public_key), HashAlgorithm.SHA256), + key_pair_2.private_key.identifier + ) + diff --git a/virgil_crypto/tests/crypto_test.py b/virgil_crypto/tests/crypto_test.py index 93ddd8d..c024070 100644 --- a/virgil_crypto/tests/crypto_test.py +++ b/virgil_crypto/tests/crypto_test.py @@ -41,15 +41,193 @@ from virgil_crypto import VirgilCrypto from virgil_crypto.errors import VirgilCryptoError from virgil_crypto.hashes import HashAlgorithm +from virgil_crypto.keys import KeyPairType class CryptoTest(unittest.TestCase): + def _crypto(self): return VirgilCrypto() def test_strtobytes(self): self.assertEqual(self._crypto().strtobytes('test'), (116, 101, 115, 116)) + def __check_key_generation(self, key_pair_type): + key_pair = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair.private_key.identifier, key_pair.public_key.identifier) + self.assertEqual(key_pair.private_key.key_type, key_pair_type) + + def __check_key_import(self, key_pair_type): + key_pair = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair.private_key.key_type, key_pair_type) + + data_1 = self._crypto().export_private_key(key_pair.private_key) + imported_private_key = self._crypto().import_private_key(data_1).private_key + self.assertEqual(key_pair.private_key, imported_private_key) + data_2 = self._crypto().export_public_key(key_pair.public_key) + imported_public_key = self._crypto().import_public_key(data_2) + self.assertEqual(key_pair.public_key, imported_public_key) + + def __check_encryption(self, key_pair_type): + key_pair_1 = self._crypto().generate_key_pair(key_pair_type) + key_pair_2 = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair_1.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_2.private_key.key_type, key_pair_type) + + data = bytearray("test data".encode()) + + encrypted_data = self._crypto().encrypt(data, key_pair_1.public_key) + decrypted_data = self._crypto().decrypt(encrypted_data, key_pair_1.private_key) + + self.assertEqual(data, decrypted_data) + self.assertRaises(VirgilCryptoFoundationError, self._crypto().decrypt, encrypted_data, key_pair_2.private_key) + + def __check_signature(self, key_pair_type): + key_pair_1 = self._crypto().generate_key_pair(key_pair_type) + key_pair_2 = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair_1.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_2.private_key.key_type, key_pair_type) + + data = bytearray("test data".encode()) + + signature = self._crypto().generate_signature(data, key_pair_1.private_key) + + self.assertTrue(self._crypto().verify_signature(data, signature, key_pair_1.public_key)) + self.assertFalse(self._crypto().verify_signature(data, signature, key_pair_2.public_key)) + + def __check_sign_then_encrypt(self, key_pair_type): + key_pair_1 = self._crypto().generate_key_pair(key_pair_type) + key_pair_2 = self._crypto().generate_key_pair(key_pair_type) + key_pair_3 = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair_1.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_2.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_3.private_key.key_type, key_pair_type) + + data = bytearray("test data".encode()) + + encrypted = self._crypto().sign_then_encrypt(data, key_pair_1.private_key, key_pair_1.public_key, key_pair_2.public_key) + decrypted = self._crypto().decrypt_then_verify(encrypted, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + + self.assertEqual(data, decrypted) + + self.assertRaises(VirgilCryptoFoundationError, self._crypto().decrypt_then_verify, encrypted, key_pair_3.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + self.assertRaises(VirgilCryptoError, self._crypto().decrypt_then_verify, encrypted, key_pair_2.private_key, key_pair_3.public_key) + + def __check_stream_sign(self, key_pair_type): + key_pair_1 = self._crypto().generate_key_pair(key_pair_type) + key_pair_2 = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair_1.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_2.private_key.key_type, key_pair_type) + + input_stream = io.BytesIO(bytearray("test data".encode())) + + signature = self._crypto().generate_stream_signature(input_stream, key_pair_1.private_key) + + input_stream_1 = io.BytesIO(bytearray("test data".encode())) + input_stream_2 = io.BytesIO(bytearray("test data".encode())) + + self.assertTrue(self._crypto().verify_stream_signature(input_stream_1, signature, key_pair_1.public_key)) + self.assertFalse(self._crypto().verify_stream_signature(input_stream_2, signature, key_pair_2.public_key)) + + def __check_stream_encryption(self, key_pair_type): + key_pair_1 = self._crypto().generate_key_pair(key_pair_type) + key_pair_2 = self._crypto().generate_key_pair(key_pair_type) + self.assertEqual(key_pair_1.private_key.key_type, key_pair_type) + self.assertEqual(key_pair_2.private_key.key_type, key_pair_type) + + data = bytearray("test data".encode()) + + encrypt_input_stream = io.BytesIO(data) + encrypt_output_stream = io.BytesIO() + self._crypto().encrypt_stream( + encrypt_input_stream, + encrypt_output_stream, + key_pair_1.public_key + ) + encrypt_stream_data = encrypt_output_stream.getvalue() + + decrypt_input_stream = io.BytesIO(encrypt_stream_data) + decrypt_output_stream = io.BytesIO() + self._crypto().decrypt_stream( + decrypt_input_stream, + decrypt_output_stream, + key_pair_1.private_key + ) + decrypt_stream_data = decrypt_output_stream.getvalue() + self.assertEqual( + data, + decrypt_stream_data + ) + + decrypt_input_stream_2 = io.BytesIO(encrypt_stream_data) + decrypt_output_stream_2 = io.BytesIO() + self.assertRaises( + VirgilCryptoFoundationError, + self._crypto().decrypt_stream, + decrypt_input_stream_2, + decrypt_output_stream_2, + key_pair_2.private_key + ) + + def __check_generate_key_using_seed(self, key_pair_type): + crypto = VirgilCrypto() + seed = crypto.generate_random_data(32) + + key_id = crypto.generate_key_pair(key_pair_type, seed=seed).private_key.identifier + + retries = 5 + while retries > 0: + key_pair = crypto.generate_key_pair(key_pair_type, seed=seed) + self.assertTrue(key_id, key_pair.private_key.identifier) + self.assertTrue(key_pair.private_key.identifier, key_pair.public_key.identifier) + self.assertEqual(key_pair.private_key.key_type, key_pair_type) + retries -= 1 + + def test_key_generation_all_key_types(self): + for key_type in [KeyPairType.CURVE25519, KeyPairType.ED25519, KeyPairType.SECP256R1, KeyPairType.RSA_2048]: + self.__check_key_generation(key_type) + + def test_key_import_all_key_types(self): + for key_type in [KeyPairType.CURVE25519, KeyPairType.ED25519, KeyPairType.SECP256R1, KeyPairType.RSA_2048]: + self.__check_key_import(key_type) + + def test_encrypt_some_data_all_key_types(self): + for key_type in [KeyPairType.CURVE25519, KeyPairType.ED25519, KeyPairType.SECP256R1, KeyPairType.RSA_2048]: + self.__check_encryption(key_type) + + def test_signature_some_data_all_key_types(self): + for key_type in [ + KeyPairType.ED25519, + KeyPairType.SECP256R1, + KeyPairType.RSA_2048 + ]: + self.__check_signature(key_type) + + def test_sign_then_encrypt_all_key_types(self): + for key_type in [ + KeyPairType.ED25519, + KeyPairType.SECP256R1, + KeyPairType.RSA_2048 + ]: + self.__check_sign_then_encrypt(key_type) + + def test_sign_stream_all_key_types(self): + for key_type in [ + KeyPairType.ED25519, + KeyPairType.SECP256R1, + KeyPairType.RSA_2048 + ]: + self.__check_stream_sign(key_type) + + def test_encrypt_stream_all_key_types(self): + for key_type in [KeyPairType.CURVE25519, KeyPairType.ED25519, KeyPairType.SECP256R1, KeyPairType.RSA_2048]: + self.__check_stream_encryption(key_type) + + def test_generate_key_using_seed_all_key_types(self): + for key_type in [KeyPairType.CURVE25519, KeyPairType.ED25519, KeyPairType.SECP256R1, KeyPairType.RSA_2048]: + self.__check_generate_key_using_seed(key_type) + + def test_import_private_key(self): key_pair = self._crypto().generate_key_pair() private_key_data = self._crypto().export_private_key(key_pair.private_key) From 310e26e49d60d0165c6a2fef10ea46c92a8bef5f Mon Sep 17 00:00:00 2001 From: Mariia Malitska Date: Mon, 1 Jul 2019 16:21:45 +0300 Subject: [PATCH 03/11] Updated support + license --- LICENSE | 14 ++++++++++++++ README.md | 13 +++---------- 2 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29c6ddb --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +The BSD 3-Clause License (BSD) + +Copyright (c) 2019, Virgil Security, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index a095a0c..58752b4 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,9 @@ ### [Introduction](#introduction) | [Library purposes](#library-purposes) | [Usage examples](#usage-examples) | [Installation](#installation) | [Docs](#docs) | [License](#license) | [Contacts](#support) ## Introduction -VirgilCrypto is a stack of security libraries (ECIES with Crypto Agility wrapped in Virgil Cryptogram) and an -open-source high-level [cryptographic library](https://github.com/VirgilSecurity/virgil-crypto) that allows you to -perform all necessary operations for securely storing and transferring data in your digital solutions. Crypto Library -is written in C++ and is suitable for mobile and server platforms. +VirgilCrypto is a stack of security libraries (ECIES with Crypto Agility wrapped in Virgil Cryptogram) and an open-source high-level [cryptographic library](https://github.com/VirgilSecurity/virgil-crypto) that allows you to perform all necessary operations for securely storing and transferring data in your digital solutions. Crypto Library is written in C++ and is suitable for mobile and server platforms. -Virgil Security, Inc., guides software developers into the forthcoming security world in which everything will be -encrypted (and passwords will be eliminated). In this world, the days of developers having to raise millions of -dollars to build a secure chat, secure email, secure file-sharing, or a secure anything have come to an end. Now -developers can instead focus on building features that give them a competitive market advantage while end-users can -enjoy the privacy and security they increasingly demand. +Virgil Security, Inc., guides software developers into the forthcoming security world in which everything will be encrypted (and passwords will be eliminated). In this world, the days of developers having to raise millions of dollars to build a secure chat, secure email, secure file-sharing, or a secure anything have come to an end. Now developers can instead focus on building features that give them a competitive market advantage while end-users can enjoy the privacy and security they increasingly demand. ## Library purposes * Asymmetric Key Generation @@ -120,4 +113,4 @@ Our developer support team is here to help you. Find out more information on our You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com. -Also, get extra help from our support team on [Slack](https://virgilsecurity.slack.com/join/shared_invite/enQtMjg4MDE4ODM3ODA4LTc2OWQwOTQ3YjNhNTQ0ZjJiZDc2NjkzYjYxNTI0YzhmNTY2ZDliMGJjYWQ5YmZiOGU5ZWEzNmJiMWZhYWVmYTM). +Also, get extra help from our support team on [Slack](https://virgilsecurity.com/join-community). From b4fd37f40bf030e07d6af6a2104a94ebd862413e Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Thu, 1 Aug 2019 17:37:57 +0300 Subject: [PATCH 04/11] Support changes from virgil-crypto-lib --- virgil_crypto/crypto.py | 41 ++++++++++++++--------- virgil_crypto/keys/virgil_private_key.py | 1 - virgil_crypto/keys/virgil_public_key.py | 1 - virgil_crypto/tests/crypto_test.py | 2 +- virgil_crypto/tests/signer_test.py | 4 +-- virgil_crypto/tests/stream_signer_test.py | 4 +-- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/virgil_crypto/crypto.py b/virgil_crypto/crypto.py index 76af680..5d6c22d 100644 --- a/virgil_crypto/crypto.py +++ b/virgil_crypto/crypto.py @@ -141,7 +141,7 @@ def import_private_key(self, key_data): private_key = key_provider.import_private_key(bytearray(key_data)) if private_key.alg_id() == AlgId.RSA: - key_type = KeyPairType.KeyType(private_key.alg_id(), private_key.key_bitlen()) + key_type = KeyPairType.KeyType(private_key.alg_id(), private_key.bitlen()) else: key_type = KeyPairType.KeyType(private_key.alg_id()) @@ -173,7 +173,7 @@ def import_public_key(self, key_data): public_key = key_provider.import_public_key(bytearray(key_data)) if public_key.alg_id() == AlgId.RSA: - key_type = KeyPairType.KeyType(public_key.alg_id(), public_key.key_bitlen()) + key_type = KeyPairType.KeyType(public_key.alg_id(), public_key.bitlen()) else: key_type = KeyPairType.KeyType(public_key.alg_id()) @@ -196,9 +196,12 @@ def export_private_key(private_key): Returns: Private key in DER format """ - serializer = KeyAsn1Serializer() - serializer.setup_defaults() - return serializer.serialize_private_key(private_key.private_key) + key_provider = KeyProvider() + rand = CtrDrbg() + key_provider.set_random(rand) + key_provider.setup_defaults() + + return key_provider.export_private_key(private_key.private_key) @staticmethod def export_public_key(public_key): @@ -211,10 +214,12 @@ def export_public_key(public_key): Returns: Key material representation bytes. """ - serializer = KeyAsn1Serializer() - serializer.setup_defaults() + key_provider = KeyProvider() + rand = CtrDrbg() + key_provider.set_random(rand) + key_provider.setup_defaults() - return serializer.serialize_public_key(public_key.public_key) + return key_provider.export_public_key(public_key.public_key) @staticmethod def extract_public_key(private_key): @@ -376,9 +381,12 @@ def generate_signature(data, private_key): Signature bytes. """ signer = Signer() + rand = CtrDrbg() + rand.setup_defaults() signer.set_hash(Sha512()) + signer.set_random(rand) signer.reset() - signer.update(bytearray(data)) + signer.append_data(bytearray(data)) signature = signer.sign(private_key.private_key) return signature @@ -397,7 +405,7 @@ def verify_signature(data, signature, public_key): """ verifier = Verifier() verifier.reset(bytearray(signature)) - verifier.update(bytearray(data)) + verifier.append_data(bytearray(data)) return verifier.verify(public_key.public_key) def encrypt_stream(self, input_stream, output_stream, *recipients): @@ -469,10 +477,13 @@ def generate_stream_signature(self, input_stream, private_key): Signature bytes. """ signer = Signer() + rand = CtrDrbg() + rand.setup_defaults() + signer.set_random(rand) signer.set_hash(Sha512()) signer.reset() - self.__for_each_chunk_input(input_stream, signer.update) + self.__for_each_chunk_input(input_stream, signer.append_data) signature = signer.sign(private_key.private_key) return signature @@ -492,7 +503,7 @@ def verify_stream_signature(self, input_stream, signature, signer_public_key): verifier = Verifier() verifier.reset(bytearray(signature)) - self.__for_each_chunk_input(input_stream, verifier.update) + self.__for_each_chunk_input(input_stream, verifier.append_data) return verifier.verify(signer_public_key.public_key) @staticmethod @@ -525,10 +536,10 @@ def compute_public_key_identifier(self, public_key): Returns: Public key identifier. """ - serializer = KeyAsn1Serializer() - serializer.setup_defaults() + key_provider = KeyProvider() + key_provider.setup_defaults() - public_key_data = serializer.serialize_public_key(public_key) + public_key_data = key_provider.export_public_key(public_key) if self.use_sha256_fingerprints: return self.compute_hash(public_key_data, HashAlgorithm.SHA256) diff --git a/virgil_crypto/keys/virgil_private_key.py b/virgil_crypto/keys/virgil_private_key.py index 051874e..583d5d0 100644 --- a/virgil_crypto/keys/virgil_private_key.py +++ b/virgil_crypto/keys/virgil_private_key.py @@ -43,5 +43,4 @@ def __init__(self, identifier=None, private_key=None, key_type=None): def __eq__(self, other): return self.identifier == other.identifier and \ - self.private_key.export_private_key() == other.private_key.export_private_key() and \ self.key_type == other.key_type diff --git a/virgil_crypto/keys/virgil_public_key.py b/virgil_crypto/keys/virgil_public_key.py index 13516e2..f083f7c 100644 --- a/virgil_crypto/keys/virgil_public_key.py +++ b/virgil_crypto/keys/virgil_public_key.py @@ -43,5 +43,4 @@ def __init__(self, identifier=None, public_key=None, key_type=None): def __eq__(self, other): return self.identifier == other.identifier and \ - self.public_key.export_public_key() == other.public_key.export_public_key() and \ self.key_type == other.key_type diff --git a/virgil_crypto/tests/crypto_test.py b/virgil_crypto/tests/crypto_test.py index c024070..f9739df 100644 --- a/virgil_crypto/tests/crypto_test.py +++ b/virgil_crypto/tests/crypto_test.py @@ -391,7 +391,7 @@ def test_private_key_identifier_is_correct(self): self.assertEqual( hashlib.sha512(bytearray(crypto_1.export_public_key(key_pair_1.public_key))).digest()[0:8], - bytearray(key_pair_1.private_key.identifier) + bytes(key_pair_1.private_key.identifier) ) crypto_2 = VirgilCrypto() diff --git a/virgil_crypto/tests/signer_test.py b/virgil_crypto/tests/signer_test.py index bed6c0e..ca66f87 100644 --- a/virgil_crypto/tests/signer_test.py +++ b/virgil_crypto/tests/signer_test.py @@ -48,11 +48,11 @@ def test_signs_and_verifies_data(self): signer = Signer() signer.set_hash(Sha512()) signer.reset() - signer.update(raw_data) + signer.append_data(raw_data) signature = signer.sign(key_pair.private_key.private_key) verifier = Verifier() verifier.reset(signature) - verifier.update(raw_data) + verifier.append_data(raw_data) is_valid = verifier.verify(key_pair.public_key.public_key) self.assertTrue(is_valid) diff --git a/virgil_crypto/tests/stream_signer_test.py b/virgil_crypto/tests/stream_signer_test.py index ac899df..0c5877d 100644 --- a/virgil_crypto/tests/stream_signer_test.py +++ b/virgil_crypto/tests/stream_signer_test.py @@ -50,12 +50,12 @@ def test_signs_and_verifies_data(self): signer = Signer() signer.set_hash(Sha512()) signer.reset() - VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, signer.update) + VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, signer.append_data) signature = signer.sign(key_pair.private_key.private_key) input_stream = io.BytesIO(raw_data) verifier = Verifier() verifier.reset(signature) - VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, verifier.update) + VirgilCrypto()._VirgilCrypto__for_each_chunk_input(input_stream, verifier.append_data) is_valid = verifier.verify(key_pair.public_key.public_key) self.assertTrue(is_valid) From debeead7662b7f784faa7c744ea4e824307e0ea3 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 18:11:05 +0300 Subject: [PATCH 05/11] Ended support for python 3.3 Added windows tests for travis ci --- .travis.yml | 17 ++++++++++++++++- Jenkinsfile | 2 +- setup.py | 1 - 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c9a1e0..1dd09e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ language: python python: - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" @@ -31,6 +30,22 @@ matrix: - os: osx language: generic env: PYTHON=3.7.1 PYTHON_VERSION=3.7 OS_NAME=darwin + - os: windows + language: shell + env: PATH=/c/Python27:/c/Python27/Scripts:$PATH + - os: windows + language: shell + env: PATH=/c/Python34:/c/Python34/Scripts:$PATH + - os: windows + language: shell + env: PATH=/c/Python35:/c/Python35/Scripts:$PATH + - os: windows + language: shell + env: PATH=/c/Python36:/c/Python36/Scripts:$PATH + - os: windows + language: shell + env: PATH=/c/Python37:/c/Python37/Scripts:$PATH + before_install: | if [ "$TRAVIS_OS_NAME" == "osx" ]; then diff --git a/Jenkinsfile b/Jenkinsfile index 6e47f4c..f1b610c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -88,7 +88,7 @@ stage('Deploy Packages'){ // Utility Functions def cleanPythonPackageBuildDirectoriesLinux(){ - sh "find virgil_crypto_lib/ -name '*.pyc' -delete" + sh "find virgil_crypto/ -name '*.pyc' -delete" sh "rm -rf ./build" sh "rm -rf *.egg-info" } diff --git a/setup.py b/setup.py index 35c92e6..0b080e7 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,6 @@ "Natural Language :: English", "Programming Language :: C++", "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", From 8198d851c9184c9bdc8c36b15e09205dcaf89493 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 19:01:38 +0300 Subject: [PATCH 06/11] Fixed travis badge in README Remove tests for python 2.7 on windows travis ci --- .travis.yml | 9 +++------ README.md | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1dd09e4..3dd6bdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,6 @@ matrix: - os: osx language: generic env: PYTHON=3.7.1 PYTHON_VERSION=3.7 OS_NAME=darwin - - os: windows - language: shell - env: PATH=/c/Python27:/c/Python27/Scripts:$PATH - os: windows language: shell env: PATH=/c/Python34:/c/Python34/Scripts:$PATH @@ -58,12 +55,12 @@ before_install: | export PATH="/Users/travis/.pyenv/shims:${PATH}" pyenv-virtualenv venv source venv/bin/activate - python --version fi + python --version install: - - pip install virgil-crypto-lib - - pip install . + - pip install virgil-crypto-lib || pip3 install virgil-crypto-lib + - pip install . || pip3 install . script: - pwd diff --git a/README.md b/README.md index a095a0c..f2cec6f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Virgil Security Python Crypto Library -[![Travis (.com)](https://img.shields.io/travis/com/VirgilSecurity/virgil-crypto-python.svg)](https://travis-ci.com/VirgilSecurity/virgil-crypto-python) [![PyPI](https://img.shields.io/pypi/v/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) [![PyPI](https://img.shields.io/pypi/wheel/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) [![PyPI](https://img.shields.io/pypi/pyversions/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) +[![Travis (.com)](https://img.shields.io/travis/com/VirgilSecurity/virgil-crypto-python/master.svg)](https://travis-ci.com/VirgilSecurity/virgil-crypto-python) [![PyPI](https://img.shields.io/pypi/v/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) [![PyPI](https://img.shields.io/pypi/wheel/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) [![PyPI](https://img.shields.io/pypi/pyversions/virgil-crypto.svg)](https://pypi.python.org/pypi/virgil-crypto) ### [Introduction](#introduction) | [Library purposes](#library-purposes) | [Usage examples](#usage-examples) | [Installation](#installation) | [Docs](#docs) | [License](#license) | [Contacts](#support) From d5cd1a8ff37918ccb7abdae6e1af2c95e40360a0 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 20:21:19 +0300 Subject: [PATCH 07/11] Added installing python to windows machines in travis ci --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3dd6bdb..bb41eee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,15 +32,33 @@ matrix: env: PYTHON=3.7.1 PYTHON_VERSION=3.7 OS_NAME=darwin - os: windows language: shell + before_install: + - choco install python2 + - python -m pip install --upgrade pip + env: PATH=/c/Python27:/c/Python27/Scripts:$PATH + - os: windows + language: shell + before_install: + - choco install python --version 3.4.2 + - python -m pip install --upgrade pip env: PATH=/c/Python34:/c/Python34/Scripts:$PATH - os: windows language: shell + before_install: + - choco install python --version 3.5.4 + - python -m pip install --upgrade pip env: PATH=/c/Python35:/c/Python35/Scripts:$PATH - os: windows language: shell + before_install: + - choco install python --version 3.6.7 + - python -m pip install --upgrade pip env: PATH=/c/Python36:/c/Python36/Scripts:$PATH - os: windows language: shell + before_install: + - choco install python 3.7.4 + - python -m pip install --upgrade pip env: PATH=/c/Python37:/c/Python37/Scripts:$PATH From 5a8c00769cb883bbf11bf89ff312bd8b7c84004c Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 20:54:29 +0300 Subject: [PATCH 08/11] Fix install python 3.7 on windows env travis ci Try fix python 3.4 env windows travis ci --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb41eee..9767b6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: before_install: - choco install python --version 3.4.2 - python -m pip install --upgrade pip - env: PATH=/c/Python34:/c/Python34/Scripts:$PATH + env: PATH=/c/Python34-64:/c/Python34-64/Scripts:$PATH - os: windows language: shell before_install: @@ -57,7 +57,7 @@ matrix: - os: windows language: shell before_install: - - choco install python 3.7.4 + - choco install python 3.7.2 - python -m pip install --upgrade pip env: PATH=/c/Python37:/c/Python37/Scripts:$PATH From 4c869c87c8e8b2842165c3c2af38fa6181082bb7 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 21:23:54 +0300 Subject: [PATCH 09/11] Fix install python 3.7 on windows travis ci Try fix python 3.4 on windows travis ci --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9767b6e..9587765 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: before_install: - choco install python --version 3.4.2 - python -m pip install --upgrade pip - env: PATH=/c/Python34-64:/c/Python34-64/Scripts:$PATH + env: PATH=/c/Python34:/c/Python34/Scripts:/c/tools/python:/c/tools/python/Scripts:$PATH - os: windows language: shell before_install: @@ -57,7 +57,7 @@ matrix: - os: windows language: shell before_install: - - choco install python 3.7.2 + - choco install python --version 3.7.2 - python -m pip install --upgrade pip env: PATH=/c/Python37:/c/Python37/Scripts:$PATH From 771f87aa3d997a3ceacc94677884000ab888d8b1 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Tue, 6 Aug 2019 21:59:23 +0300 Subject: [PATCH 10/11] Remove python 3.4 windows env from travis ci --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9587765..49547eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,12 +36,6 @@ matrix: - choco install python2 - python -m pip install --upgrade pip env: PATH=/c/Python27:/c/Python27/Scripts:$PATH - - os: windows - language: shell - before_install: - - choco install python --version 3.4.2 - - python -m pip install --upgrade pip - env: PATH=/c/Python34:/c/Python34/Scripts:/c/tools/python:/c/tools/python/Scripts:$PATH - os: windows language: shell before_install: From d1a2177f195cb8336da60c6114ca0ce2f4758af0 Mon Sep 17 00:00:00 2001 From: Imelstorm Date: Thu, 8 Aug 2019 11:57:19 +0300 Subject: [PATCH 11/11] Renamed sign_then_encrypt -> sign_and_encrypt and decrypt_then_verify -> decrypt_and_verify --- virgil_crypto/crypto.py | 4 ++-- virgil_crypto/tests/compatibility_test.py | 6 +++--- virgil_crypto/tests/crypto_test.py | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/virgil_crypto/crypto.py b/virgil_crypto/crypto.py index 5d6c22d..5268c8e 100644 --- a/virgil_crypto/crypto.py +++ b/virgil_crypto/crypto.py @@ -288,7 +288,7 @@ def decrypt(data, private_key): result += cipher.finish_decryption() return result - def sign_then_encrypt(self, data, private_key, *recipients): + def sign_and_encrypt(self, data, private_key, *recipients): # type: (Union[Tuple[int], List[int], bytearray], VirgilPrivateKey, List[VirgilPublicKey]) -> Union[Tuple[int], bytearray] """Signs and encrypts the data. @@ -323,7 +323,7 @@ def sign_then_encrypt(self, data, private_key, *recipients): return result - def decrypt_then_verify(self, data, private_key, signers_public_keys): + def decrypt_and_verify(self, data, private_key, signers_public_keys): # type: (Union[Tuple[int], List[int], bytearray], VirgilPrivateKey, Union[List[VirgilPublicKey], VirgilPublicKey]) -> Union[Tuple[int], bytearray] """Decrypts and verifies the data. diff --git a/virgil_crypto/tests/compatibility_test.py b/virgil_crypto/tests/compatibility_test.py index 796ec19..5d218db 100644 --- a/virgil_crypto/tests/compatibility_test.py +++ b/virgil_crypto/tests/compatibility_test.py @@ -73,7 +73,7 @@ def test_sign_then_encrypt_single_recipient(self): data = self._compatibility_data["sign_then_encrypt_single_recipient"] private_key = self._crypto.import_private_key(data["private_key"]).private_key public_key = self._crypto.extract_public_key(private_key) - decrypted_data = self._crypto.decrypt_then_verify( + decrypted_data = self._crypto.decrypt_and_verify( data["cipher_data"], private_key, public_key @@ -87,7 +87,7 @@ def test_sign_then_encrypt_multiple_recipients(self): self.assertGreater(len(private_keys), 0) public_key = self._crypto.extract_public_key(private_keys[0]) for private_key in private_keys: - decrypted_data = self._crypto.decrypt_then_verify( + decrypted_data = self._crypto.decrypt_and_verify( data["cipher_data"], private_key, public_key @@ -111,7 +111,7 @@ def test_decrypt_then_verify_multiple_signers(self): data = self._compatibility_data["sign_then_encrypt_multiple_signers"] private_key = self._crypto.import_private_key(data["private_key"]).private_key public_keys = [self._crypto.import_public_key(pk) for pk in data["public_keys"]] - decrypted_data = self._crypto.decrypt_then_verify( + decrypted_data = self._crypto.decrypt_and_verify( data["cipher_data"], private_key, public_keys diff --git a/virgil_crypto/tests/crypto_test.py b/virgil_crypto/tests/crypto_test.py index f9739df..aefcdb1 100644 --- a/virgil_crypto/tests/crypto_test.py +++ b/virgil_crypto/tests/crypto_test.py @@ -105,13 +105,13 @@ def __check_sign_then_encrypt(self, key_pair_type): data = bytearray("test data".encode()) - encrypted = self._crypto().sign_then_encrypt(data, key_pair_1.private_key, key_pair_1.public_key, key_pair_2.public_key) - decrypted = self._crypto().decrypt_then_verify(encrypted, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + encrypted = self._crypto().sign_and_encrypt(data, key_pair_1.private_key, key_pair_1.public_key, key_pair_2.public_key) + decrypted = self._crypto().decrypt_and_verify(encrypted, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) self.assertEqual(data, decrypted) - self.assertRaises(VirgilCryptoFoundationError, self._crypto().decrypt_then_verify, encrypted, key_pair_3.private_key, [key_pair_1.public_key, key_pair_2.public_key]) - self.assertRaises(VirgilCryptoError, self._crypto().decrypt_then_verify, encrypted, key_pair_2.private_key, key_pair_3.public_key) + self.assertRaises(VirgilCryptoFoundationError, self._crypto().decrypt_and_verify, encrypted, key_pair_3.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + self.assertRaises(VirgilCryptoError, self._crypto().decrypt_and_verify, encrypted, key_pair_2.private_key, key_pair_3.public_key) def __check_stream_sign(self, key_pair_type): key_pair_1 = self._crypto().generate_key_pair(key_pair_type) @@ -442,13 +442,13 @@ def test_sign_then_encrypt(self): key_pair_3 = crypto.generate_key_pair() data = [1, 2, 3] - cipher_data = crypto.sign_then_encrypt(data, key_pair_1.private_key, key_pair_2.public_key) + cipher_data = crypto.sign_and_encrypt(data, key_pair_1.private_key, key_pair_2.public_key) - decrypted_data = crypto.decrypt_then_verify(cipher_data, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) + decrypted_data = crypto.decrypt_and_verify(cipher_data, key_pair_2.private_key, [key_pair_1.public_key, key_pair_2.public_key]) self.assertEqual(data, list(decrypted_data)) - self.assertRaises(VirgilCryptoError, crypto.decrypt_then_verify, cipher_data, key_pair_2.private_key, key_pair_3.public_key) + self.assertRaises(VirgilCryptoError, crypto.decrypt_and_verify, cipher_data, key_pair_2.private_key, key_pair_3.public_key) def test_generate_key_using_seed(self): crypto = VirgilCrypto()