# Copyright 2013-2018 Donald Stufft and individual contributors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import absolute_import, division, print_function import binascii import pytest from utils import flip_byte from nacl.encoding import HexEncoder from nacl.exceptions import CryptoError from nacl.secret import SecretBox VECTORS = [ # Key, Nonce, Plaintext, Ciphertext ( b"1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389", b"69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37", (b"be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5e" b"cbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb310e3be8" b"250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde048977eb4" b"8f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705"), (b"f3ffc7703f9400e52a7dfb4b3d3305d98e993b9f48681273c29650ba32fc76ce483" b"32ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c97271d2c2" b"0f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae902243685" b"17acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b37973f622a43d" b"14a6599b1f654cb45a74e355a5"), ), ] def test_secret_box_creation(): SecretBox( b"ec2bee2d5be613ca82e377c96a0bf2220d823ce980cdff6279473edc52862798", encoder=HexEncoder, ) def test_secret_box_bytes(): s = SecretBox( b"ec2bee2d5be613ca82e377c96a0bf2220d823ce980cdff6279473edc52862798", encoder=HexEncoder, ) assert bytes(s) == s._key @pytest.mark.parametrize(("key", "nonce", "plaintext", "ciphertext"), VECTORS) def test_secret_box_encryption(key, nonce, plaintext, ciphertext): box = SecretBox(key, encoder=HexEncoder) encrypted = box.encrypt( binascii.unhexlify(plaintext), binascii.unhexlify(nonce), encoder=HexEncoder, ) expected = binascii.hexlify( binascii.unhexlify(nonce) + binascii.unhexlify(ciphertext), ) assert encrypted == expected assert encrypted.nonce == nonce assert encrypted.ciphertext == ciphertext @pytest.mark.parametrize(("key", "nonce", "plaintext", "ciphertext"), VECTORS) def test_secret_box_decryption(key, nonce, plaintext, ciphertext): box = SecretBox(key, encoder=HexEncoder) nonce = binascii.unhexlify(nonce) decrypted = binascii.hexlify( box.decrypt(ciphertext, nonce, encoder=HexEncoder), ) assert decrypted == plaintext @pytest.mark.parametrize(("key", "nonce", "plaintext", "ciphertext"), VECTORS) def test_secret_box_decryption_combined(key, nonce, plaintext, ciphertext): box = SecretBox(key, encoder=HexEncoder) combined = binascii.hexlify( binascii.unhexlify(nonce) + binascii.unhexlify(ciphertext), ) decrypted = binascii.hexlify(box.decrypt(combined, encoder=HexEncoder)) assert decrypted == plaintext @pytest.mark.parametrize(("key", "nonce", "plaintext", "ciphertext"), VECTORS) def test_secret_box_optional_nonce(key, nonce, plaintext, ciphertext): box = SecretBox(key, encoder=HexEncoder) encrypted = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder) decrypted = binascii.hexlify(box.decrypt(encrypted, encoder=HexEncoder)) assert decrypted == plaintext @pytest.mark.parametrize(("key", "nonce", "plaintext", "ciphertext"), VECTORS) def test_secret_box_encryption_generates_different_nonces( key, nonce, plaintext, ciphertext): box = SecretBox(key, encoder=HexEncoder) nonce_0 = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder).nonce nonce_1 = box.encrypt(binascii.unhexlify(plaintext), encoder=HexEncoder).nonce assert nonce_0 != nonce_1 def test_secret_box_wrong_lengths(): with pytest.raises(ValueError): SecretBox(b"") box = SecretBox( b"ec2bee2d5be613ca82e377c96a0bf2220d823ce980cdff6279473edc52862798", encoder=HexEncoder, ) with pytest.raises(ValueError): box.encrypt(b"", b"") with pytest.raises(ValueError): box.decrypt(b"", b"") def check_type_error(expected, f, *args): with pytest.raises(TypeError) as e: f(*args) assert expected in str(e) def test_wrong_types(): box = SecretBox(b"11" * 32, encoder=HexEncoder) check_type_error("SecretBox must be created from 32 bytes", SecretBox, 12) check_type_error("SecretBox must be created from 32 bytes", SecretBox, box) def test_secret_box_bad_decryption(): box = SecretBox(b"\x11" * 32) ciphertext = box.encrypt(b"hello") with pytest.raises(CryptoError): # changes the nonce box.decrypt(flip_byte(ciphertext, 0)) with pytest.raises(CryptoError): # changes ciphertext box.decrypt(flip_byte(ciphertext, 24)) with pytest.raises(CryptoError): # changes MAC tag box.decrypt(flip_byte(ciphertext, len(ciphertext) - 1)) with pytest.raises(CryptoError): # completely changes ciphertext and tag box.decrypt(ciphertext + b"\x00") with pytest.raises(CryptoError): # completely changes everything box.decrypt(b"\x00" + ciphertext)