1# Copyright 2013-2019 Donald Stufft and individual contributors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from __future__ import absolute_import, division, print_function 16 17from six import integer_types 18 19from nacl import exceptions as exc 20from nacl._sodium import ffi, lib 21from nacl.exceptions import ensure 22 23 24crypto_generichash_BYTES = lib.crypto_generichash_blake2b_bytes() 25crypto_generichash_BYTES_MIN = lib.crypto_generichash_blake2b_bytes_min() 26crypto_generichash_BYTES_MAX = lib.crypto_generichash_blake2b_bytes_max() 27crypto_generichash_KEYBYTES = lib.crypto_generichash_blake2b_keybytes() 28crypto_generichash_KEYBYTES_MIN = lib.crypto_generichash_blake2b_keybytes_min() 29crypto_generichash_KEYBYTES_MAX = lib.crypto_generichash_blake2b_keybytes_max() 30crypto_generichash_SALTBYTES = lib.crypto_generichash_blake2b_saltbytes() 31crypto_generichash_PERSONALBYTES = \ 32 lib.crypto_generichash_blake2b_personalbytes() 33crypto_generichash_STATEBYTES = lib.crypto_generichash_statebytes() 34 35_OVERLONG = '{0} length greater than {1} bytes' 36_TOOBIG = '{0} greater than {1}' 37 38 39def _checkparams(digest_size, key, salt, person): 40 """Check hash paramters""" 41 ensure(isinstance(key, bytes), 42 'Key must be a bytes sequence', 43 raising=exc.TypeError) 44 45 ensure(isinstance(salt, bytes), 46 'Salt must be a bytes sequence', 47 raising=exc.TypeError) 48 49 ensure(isinstance(person, bytes), 50 'Person must be a bytes sequence', 51 raising=exc.TypeError) 52 53 ensure(isinstance(digest_size, integer_types), 54 'Digest size must be an integer number', 55 raising=exc.TypeError) 56 57 ensure(digest_size <= crypto_generichash_BYTES_MAX, 58 _TOOBIG.format("Digest_size", crypto_generichash_BYTES_MAX), 59 raising=exc.ValueError) 60 61 ensure(len(key) <= crypto_generichash_KEYBYTES_MAX, 62 _OVERLONG.format("Key", crypto_generichash_KEYBYTES_MAX), 63 raising=exc.ValueError) 64 65 ensure(len(salt) <= crypto_generichash_SALTBYTES, 66 _OVERLONG.format("Salt", crypto_generichash_SALTBYTES), 67 raising=exc.ValueError) 68 69 ensure(len(person) <= crypto_generichash_PERSONALBYTES, 70 _OVERLONG.format("Person", crypto_generichash_PERSONALBYTES), 71 raising=exc.ValueError) 72 73 74def generichash_blake2b_salt_personal(data, 75 digest_size=crypto_generichash_BYTES, 76 key=b'', salt=b'', person=b''): 77 """One shot hash interface 78 79 :param data: the input data to the hash function 80 :param digest_size: must be at most 81 :py:data:`.crypto_generichash_BYTES_MAX`; 82 the default digest size is 83 :py:data:`.crypto_generichash_BYTES` 84 :type digest_size: int 85 :param key: must be at most 86 :py:data:`.crypto_generichash_KEYBYTES_MAX` long 87 :type key: bytes 88 :param salt: must be at most 89 :py:data:`.crypto_generichash_SALTBYTES` long; 90 will be zero-padded if needed 91 :type salt: bytes 92 :param person: must be at most 93 :py:data:`.crypto_generichash_PERSONALBYTES` long: 94 will be zero-padded if needed 95 :type person: bytes 96 :return: digest_size long digest 97 :rtype: bytes 98 """ 99 100 _checkparams(digest_size, key, salt, person) 101 102 ensure(isinstance(data, bytes), 103 'Input data must be a bytes sequence', 104 raising=exc.TypeError) 105 106 digest = ffi.new("unsigned char[]", digest_size) 107 108 # both _salt and _personal must be zero-padded to the correct length 109 _salt = ffi.new("unsigned char []", crypto_generichash_SALTBYTES) 110 _person = ffi.new("unsigned char []", crypto_generichash_PERSONALBYTES) 111 112 ffi.memmove(_salt, salt, len(salt)) 113 ffi.memmove(_person, person, len(person)) 114 115 rc = lib.crypto_generichash_blake2b_salt_personal(digest, digest_size, 116 data, len(data), 117 key, len(key), 118 _salt, _person) 119 ensure(rc == 0, 'Unexpected failure', 120 raising=exc.RuntimeError) 121 122 return ffi.buffer(digest, digest_size)[:] 123 124 125class Blake2State(object): 126 """ 127 Python-level wrapper for the crypto_generichash_blake2b state buffer 128 """ 129 __slots__ = ['_statebuf', 'digest_size'] 130 131 def __init__(self, digest_size): 132 self._statebuf = ffi.new("unsigned char[]", 133 crypto_generichash_STATEBYTES) 134 self.digest_size = digest_size 135 136 def __reduce__(self): 137 """ 138 Raise the same exception as hashlib's blake implementation 139 on copy.copy() 140 """ 141 raise TypeError("can't pickle {} objects".format( 142 self.__class__.__name__)) 143 144 def copy(self): 145 _st = self.__class__(self.digest_size) 146 ffi.memmove(_st._statebuf, 147 self._statebuf, crypto_generichash_STATEBYTES) 148 return _st 149 150 151def generichash_blake2b_init(key=b'', salt=b'', 152 person=b'', 153 digest_size=crypto_generichash_BYTES): 154 """ 155 Create a new initialized blake2b hash state 156 157 :param key: must be at most 158 :py:data:`.crypto_generichash_KEYBYTES_MAX` long 159 :type key: bytes 160 :param salt: must be at most 161 :py:data:`.crypto_generichash_SALTBYTES` long; 162 will be zero-padded if needed 163 :type salt: bytes 164 :param person: must be at most 165 :py:data:`.crypto_generichash_PERSONALBYTES` long: 166 will be zero-padded if needed 167 :type person: bytes 168 :param digest_size: must be at most 169 :py:data:`.crypto_generichash_BYTES_MAX`; 170 the default digest size is 171 :py:data:`.crypto_generichash_BYTES` 172 :type digest_size: int 173 :return: a initialized :py:class:`.Blake2State` 174 :rtype: object 175 """ 176 177 _checkparams(digest_size, key, salt, person) 178 179 state = Blake2State(digest_size) 180 181 # both _salt and _personal must be zero-padded to the correct length 182 _salt = ffi.new("unsigned char []", crypto_generichash_SALTBYTES) 183 _person = ffi.new("unsigned char []", crypto_generichash_PERSONALBYTES) 184 185 ffi.memmove(_salt, salt, len(salt)) 186 ffi.memmove(_person, person, len(person)) 187 188 rc = lib.crypto_generichash_blake2b_init_salt_personal(state._statebuf, 189 key, len(key), 190 digest_size, 191 _salt, _person) 192 ensure(rc == 0, 'Unexpected failure', 193 raising=exc.RuntimeError) 194 195 return state 196 197 198def generichash_blake2b_update(state, data): 199 """Update the blake2b hash state 200 201 :param state: a initialized Blake2bState object as returned from 202 :py:func:`.crypto_generichash_blake2b_init` 203 :type state: :py:class:`.Blake2State` 204 :param data: 205 :type data: bytes 206 """ 207 208 ensure(isinstance(state, Blake2State), 209 'State must be a Blake2State object', 210 raising=exc.TypeError) 211 212 ensure(isinstance(data, bytes), 213 'Input data must be a bytes sequence', 214 raising=exc.TypeError) 215 216 rc = lib.crypto_generichash_blake2b_update(state._statebuf, 217 data, len(data)) 218 ensure(rc == 0, 'Unexpected failure', 219 raising=exc.RuntimeError) 220 221 222def generichash_blake2b_final(state): 223 """Finalize the blake2b hash state and return the digest. 224 225 :param state: a initialized Blake2bState object as returned from 226 :py:func:`.crypto_generichash_blake2b_init` 227 :type state: :py:class:`.Blake2State` 228 :return: the blake2 digest of the passed-in data stream 229 :rtype: bytes 230 """ 231 232 ensure(isinstance(state, Blake2State), 233 'State must be a Blake2State object', 234 raising=exc.TypeError) 235 236 _digest = ffi.new("unsigned char[]", crypto_generichash_BYTES_MAX) 237 rc = lib.crypto_generichash_blake2b_final(state._statebuf, 238 _digest, state.digest_size) 239 240 ensure(rc == 0, 'Unexpected failure', 241 raising=exc.RuntimeError) 242 return ffi.buffer(_digest, state.digest_size)[:] 243