1# Copyright 2013 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 nacl import exceptions as exc 18from nacl._sodium import ffi, lib 19from nacl.exceptions import ensure 20 21 22crypto_sign_BYTES = lib.crypto_sign_bytes() 23# crypto_sign_SEEDBYTES = lib.crypto_sign_seedbytes() 24crypto_sign_SEEDBYTES = lib.crypto_sign_secretkeybytes() // 2 25crypto_sign_PUBLICKEYBYTES = lib.crypto_sign_publickeybytes() 26crypto_sign_SECRETKEYBYTES = lib.crypto_sign_secretkeybytes() 27 28crypto_sign_curve25519_BYTES = lib.crypto_box_secretkeybytes() 29 30crypto_sign_ed25519ph_STATEBYTES = lib.crypto_sign_ed25519ph_statebytes() 31 32 33def crypto_sign_keypair(): 34 """ 35 Returns a randomly generated public key and secret key. 36 37 :rtype: (bytes(public_key), bytes(secret_key)) 38 """ 39 pk = ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES) 40 sk = ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES) 41 42 rc = lib.crypto_sign_keypair(pk, sk) 43 ensure(rc == 0, 44 'Unexpected library error', 45 raising=exc.RuntimeError) 46 47 return ( 48 ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:], 49 ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:], 50 ) 51 52 53def crypto_sign_seed_keypair(seed): 54 """ 55 Computes and returns the public key and secret key using the seed ``seed``. 56 57 :param seed: bytes 58 :rtype: (bytes(public_key), bytes(secret_key)) 59 """ 60 if len(seed) != crypto_sign_SEEDBYTES: 61 raise exc.ValueError("Invalid seed") 62 63 pk = ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES) 64 sk = ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES) 65 66 rc = lib.crypto_sign_seed_keypair(pk, sk, seed) 67 ensure(rc == 0, 68 'Unexpected library error', 69 raising=exc.RuntimeError) 70 71 return ( 72 ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:], 73 ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:], 74 ) 75 76 77def crypto_sign(message, sk): 78 """ 79 Signs the message ``message`` using the secret key ``sk`` and returns the 80 signed message. 81 82 :param message: bytes 83 :param sk: bytes 84 :rtype: bytes 85 """ 86 signed = ffi.new("unsigned char[]", len(message) + crypto_sign_BYTES) 87 signed_len = ffi.new("unsigned long long *") 88 89 rc = lib.crypto_sign(signed, signed_len, message, len(message), sk) 90 ensure(rc == 0, 91 'Unexpected library error', 92 raising=exc.RuntimeError) 93 94 return ffi.buffer(signed, signed_len[0])[:] 95 96 97def crypto_sign_open(signed, pk): 98 """ 99 Verifies the signature of the signed message ``signed`` using the public 100 key ``pk`` and returns the unsigned message. 101 102 :param signed: bytes 103 :param pk: bytes 104 :rtype: bytes 105 """ 106 message = ffi.new("unsigned char[]", len(signed)) 107 message_len = ffi.new("unsigned long long *") 108 109 if lib.crypto_sign_open( 110 message, message_len, signed, len(signed), pk) != 0: 111 raise exc.BadSignatureError("Signature was forged or corrupt") 112 113 return ffi.buffer(message, message_len[0])[:] 114 115 116def crypto_sign_ed25519_pk_to_curve25519(public_key_bytes): 117 """ 118 Converts a public Ed25519 key (encoded as bytes ``public_key_bytes``) to 119 a public Curve25519 key as bytes. 120 121 Raises a ValueError if ``public_key_bytes`` is not of length 122 ``crypto_sign_PUBLICKEYBYTES`` 123 124 :param public_key_bytes: bytes 125 :rtype: bytes 126 """ 127 if len(public_key_bytes) != crypto_sign_PUBLICKEYBYTES: 128 raise exc.ValueError("Invalid curve public key") 129 130 curve_public_key_len = crypto_sign_curve25519_BYTES 131 curve_public_key = ffi.new("unsigned char[]", curve_public_key_len) 132 133 rc = lib.crypto_sign_ed25519_pk_to_curve25519(curve_public_key, 134 public_key_bytes) 135 ensure(rc == 0, 136 'Unexpected library error', 137 raising=exc.RuntimeError) 138 139 return ffi.buffer(curve_public_key, curve_public_key_len)[:] 140 141 142def crypto_sign_ed25519_sk_to_curve25519(secret_key_bytes): 143 """ 144 Converts a secret Ed25519 key (encoded as bytes ``secret_key_bytes``) to 145 a secret Curve25519 key as bytes. 146 147 Raises a ValueError if ``secret_key_bytes``is not of length 148 ``crypto_sign_SECRETKEYBYTES`` 149 150 :param secret_key_bytes: bytes 151 :rtype: bytes 152 """ 153 if len(secret_key_bytes) != crypto_sign_SECRETKEYBYTES: 154 raise exc.ValueError("Invalid curve secret key") 155 156 curve_secret_key_len = crypto_sign_curve25519_BYTES 157 curve_secret_key = ffi.new("unsigned char[]", curve_secret_key_len) 158 159 rc = lib.crypto_sign_ed25519_sk_to_curve25519(curve_secret_key, 160 secret_key_bytes) 161 ensure(rc == 0, 162 'Unexpected library error', 163 raising=exc.RuntimeError) 164 165 return ffi.buffer(curve_secret_key, curve_secret_key_len)[:] 166 167 168def crypto_sign_ed25519_sk_to_pk(secret_key_bytes): 169 """ 170 Extract the public Ed25519 key from a secret Ed25519 key (encoded 171 as bytes ``secret_key_bytes``). 172 173 Raises a ValueError if ``secret_key_bytes``is not of length 174 ``crypto_sign_SECRETKEYBYTES`` 175 176 :param secret_key_bytes: bytes 177 :rtype: bytes 178 """ 179 if len(secret_key_bytes) != crypto_sign_SECRETKEYBYTES: 180 raise exc.ValueError("Invalid secret key") 181 182 return secret_key_bytes[crypto_sign_SEEDBYTES:] 183 184 185def crypto_sign_ed25519_sk_to_seed(secret_key_bytes): 186 """ 187 Extract the seed from a secret Ed25519 key (encoded 188 as bytes ``secret_key_bytes``). 189 190 Raises a ValueError if ``secret_key_bytes``is not of length 191 ``crypto_sign_SECRETKEYBYTES`` 192 193 :param secret_key_bytes: bytes 194 :rtype: bytes 195 """ 196 if len(secret_key_bytes) != crypto_sign_SECRETKEYBYTES: 197 raise exc.ValueError("Invalid secret key") 198 199 return secret_key_bytes[:crypto_sign_SEEDBYTES] 200 201 202class crypto_sign_ed25519ph_state(object): 203 """ 204 State object wrapping the sha-512 state used in ed25519ph computation 205 """ 206 __slots__ = ['state'] 207 208 def __init__(self): 209 self.state = ffi.new('unsigned char[]', 210 crypto_sign_ed25519ph_STATEBYTES) 211 212 rc = lib.crypto_sign_ed25519ph_init(self.state) 213 214 ensure(rc == 0, 215 'Unexpected library error', 216 raising=exc.RuntimeError) 217 218 219def crypto_sign_ed25519ph_update(edph, pmsg): 220 """ 221 Update the hash state wrapped in edph 222 223 :param edph: the ed25519ph state being updated 224 :type edph: crypto_sign_ed25519ph_state 225 :param pmsg: the partial message 226 :type pmsg: bytes 227 :rtype: None 228 """ 229 ensure(isinstance(edph, crypto_sign_ed25519ph_state), 230 'edph parameter must be a ed25519ph_state object', 231 raising=exc.TypeError) 232 ensure(isinstance(pmsg, bytes), 233 'pmsg parameter must be a bytes object', 234 raising=exc.TypeError) 235 rc = lib.crypto_sign_ed25519ph_update(edph.state, 236 pmsg, 237 len(pmsg)) 238 ensure(rc == 0, 239 'Unexpected library error', 240 raising=exc.RuntimeError) 241 242 243def crypto_sign_ed25519ph_final_create(edph, 244 sk): 245 """ 246 Create a signature for the data hashed in edph 247 using the secret key sk 248 249 :param edph: the ed25519ph state for the data 250 being signed 251 :type edph: crypto_sign_ed25519ph_state 252 :param sk: the ed25519 secret part of the signing key 253 :type sk: bytes 254 :return: ed25519ph signature 255 :rtype: bytes 256 """ 257 ensure(isinstance(edph, crypto_sign_ed25519ph_state), 258 'edph parameter must be a ed25519ph_state object', 259 raising=exc.TypeError) 260 ensure(isinstance(sk, bytes), 261 'secret key parameter must be a bytes object', 262 raising=exc.TypeError) 263 ensure(len(sk) == crypto_sign_SECRETKEYBYTES, 264 ('secret key must be {0} ' 265 'bytes long').format(crypto_sign_SECRETKEYBYTES), 266 raising=exc.TypeError) 267 signature = ffi.new("unsigned char[]", crypto_sign_BYTES) 268 rc = lib.crypto_sign_ed25519ph_final_create(edph.state, 269 signature, 270 ffi.NULL, 271 sk) 272 ensure(rc == 0, 273 'Unexpected library error', 274 raising=exc.RuntimeError) 275 276 return ffi.buffer(signature, crypto_sign_BYTES)[:] 277 278 279def crypto_sign_ed25519ph_final_verify(edph, 280 signature, 281 pk): 282 """ 283 Verify a prehashed signature using the public key pk 284 285 :param edph: the ed25519ph state for the data 286 being verified 287 :type edph: crypto_sign_ed25519ph_state 288 :param signature: the signature being verified 289 :type signature: bytes 290 :param pk: the ed25519 public part of the signing key 291 :type pk: bytes 292 :return: True if the signature is valid 293 :rtype: boolean 294 :raises exc.BadSignatureError: if the signature is not valid 295 """ 296 ensure(isinstance(edph, crypto_sign_ed25519ph_state), 297 'edph parameter must be a ed25519ph_state object', 298 raising=exc.TypeError) 299 ensure(isinstance(signature, bytes), 300 'signature parameter must be a bytes object', 301 raising=exc.TypeError) 302 ensure(len(signature) == crypto_sign_BYTES, 303 ('signature must be {0} ' 304 'bytes long').format(crypto_sign_BYTES), 305 raising=exc.TypeError) 306 ensure(isinstance(pk, bytes), 307 'public key parameter must be a bytes object', 308 raising=exc.TypeError) 309 ensure(len(pk) == crypto_sign_PUBLICKEYBYTES, 310 ('public key must be {0} ' 311 'bytes long').format(crypto_sign_PUBLICKEYBYTES), 312 raising=exc.TypeError) 313 rc = lib.crypto_sign_ed25519ph_final_verify(edph.state, 314 signature, 315 pk) 316 if rc != 0: 317 raise exc.BadSignatureError("Signature was forged or corrupt") 318 319 return True 320