1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import pytest
from cryptography.exceptions import _Reasons
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.twofactor import InvalidToken
from cryptography.hazmat.primitives.twofactor.totp import TOTP
from ....utils import (
load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm
)
vectors = load_vectors_from_file(
"twofactor/rfc-6238.txt", load_nist_vectors)
@pytest.mark.requires_backend_interface(interface=HMACBackend)
class TestTOTP(object):
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA1()),
skip_message="Does not support HMAC-SHA1."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA1"])
def test_generate_sha1(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA1(), 30, backend)
assert totp.generate(time) == totp_value
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA256()),
skip_message="Does not support HMAC-SHA256."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA256"])
def test_generate_sha256(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA256(), 30, backend)
assert totp.generate(time) == totp_value
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA512()),
skip_message="Does not support HMAC-SHA512."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA512"])
def test_generate_sha512(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA512(), 30, backend)
assert totp.generate(time) == totp_value
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA1()),
skip_message="Does not support HMAC-SHA1."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA1"])
def test_verify_sha1(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA1(), 30, backend)
assert totp.verify(totp_value, time) is None
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA256()),
skip_message="Does not support HMAC-SHA256."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA256"])
def test_verify_sha256(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA256(), 30, backend)
assert totp.verify(totp_value, time) is None
@pytest.mark.supported(
only_if=lambda backend: backend.hmac_supported(hashes.SHA512()),
skip_message="Does not support HMAC-SHA512."
)
@pytest.mark.parametrize(
"params", [i for i in vectors if i["mode"] == b"SHA512"])
def test_verify_sha512(self, backend, params):
secret = params["secret"]
time = int(params["time"])
totp_value = params["totp"]
totp = TOTP(secret, 8, hashes.SHA512(), 30, backend)
assert totp.verify(totp_value, time) is None
def test_invalid_verify(self, backend):
secret = b"12345678901234567890"
time = 59
totp = TOTP(secret, 8, hashes.SHA1(), 30, backend)
with pytest.raises(InvalidToken):
totp.verify(b"12345678", time)
def test_floating_point_time_generate(self, backend):
secret = b"12345678901234567890"
time = 59.1
totp = TOTP(secret, 8, hashes.SHA1(), 30, backend)
assert totp.generate(time) == b"94287082"
def test_get_provisioning_uri(self, backend):
secret = b"12345678901234567890"
totp = TOTP(secret, 6, hashes.SHA1(), 30, backend=backend)
assert totp.get_provisioning_uri("Alice Smith", None) == (
"otpauth://totp/Alice%20Smith?digits=6&secret=GEZDGNBVG"
"Y3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&period=30")
assert totp.get_provisioning_uri("Alice Smith", 'World') == (
"otpauth://totp/World:Alice%20Smith?digits=6&secret=GEZ"
"DGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&issuer=World"
"&period=30")
def test_buffer_protocol(self, backend):
key = bytearray(b"a long key with lots of entropy goes here")
totp = TOTP(key, 8, hashes.SHA512(), 30, backend)
time = 60
assert totp.generate(time) == b"53049576"
def test_invalid_backend():
secret = b"12345678901234567890"
pretend_backend = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
TOTP(secret, 8, hashes.SHA1(), 30, pretend_backend)
|