1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4 5from __future__ import absolute_import, division, print_function 6 7from cryptography import exceptions, utils 8from cryptography.hazmat.primitives import serialization 9from cryptography.hazmat.primitives.asymmetric.ed25519 import ( 10 Ed25519PrivateKey, 11 Ed25519PublicKey, 12 _ED25519_KEY_SIZE, 13 _ED25519_SIG_SIZE, 14) 15 16 17@utils.register_interface(Ed25519PublicKey) 18class _Ed25519PublicKey(object): 19 def __init__(self, backend, evp_pkey): 20 self._backend = backend 21 self._evp_pkey = evp_pkey 22 23 def public_bytes(self, encoding, format): 24 if ( 25 encoding is serialization.Encoding.Raw 26 or format is serialization.PublicFormat.Raw 27 ): 28 if ( 29 encoding is not serialization.Encoding.Raw 30 or format is not serialization.PublicFormat.Raw 31 ): 32 raise ValueError( 33 "When using Raw both encoding and format must be Raw" 34 ) 35 36 return self._raw_public_bytes() 37 38 return self._backend._public_key_bytes( 39 encoding, format, self, self._evp_pkey, None 40 ) 41 42 def _raw_public_bytes(self): 43 buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) 44 buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) 45 res = self._backend._lib.EVP_PKEY_get_raw_public_key( 46 self._evp_pkey, buf, buflen 47 ) 48 self._backend.openssl_assert(res == 1) 49 self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) 50 return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] 51 52 def verify(self, signature, data): 53 evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() 54 self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) 55 evp_md_ctx = self._backend._ffi.gc( 56 evp_md_ctx, self._backend._lib.EVP_MD_CTX_free 57 ) 58 res = self._backend._lib.EVP_DigestVerifyInit( 59 evp_md_ctx, 60 self._backend._ffi.NULL, 61 self._backend._ffi.NULL, 62 self._backend._ffi.NULL, 63 self._evp_pkey, 64 ) 65 self._backend.openssl_assert(res == 1) 66 res = self._backend._lib.EVP_DigestVerify( 67 evp_md_ctx, signature, len(signature), data, len(data) 68 ) 69 if res != 1: 70 self._backend._consume_errors() 71 raise exceptions.InvalidSignature 72 73 74@utils.register_interface(Ed25519PrivateKey) 75class _Ed25519PrivateKey(object): 76 def __init__(self, backend, evp_pkey): 77 self._backend = backend 78 self._evp_pkey = evp_pkey 79 80 def public_key(self): 81 buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) 82 buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) 83 res = self._backend._lib.EVP_PKEY_get_raw_public_key( 84 self._evp_pkey, buf, buflen 85 ) 86 self._backend.openssl_assert(res == 1) 87 self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) 88 public_bytes = self._backend._ffi.buffer(buf)[:] 89 return self._backend.ed25519_load_public_bytes(public_bytes) 90 91 def sign(self, data): 92 evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() 93 self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) 94 evp_md_ctx = self._backend._ffi.gc( 95 evp_md_ctx, self._backend._lib.EVP_MD_CTX_free 96 ) 97 res = self._backend._lib.EVP_DigestSignInit( 98 evp_md_ctx, 99 self._backend._ffi.NULL, 100 self._backend._ffi.NULL, 101 self._backend._ffi.NULL, 102 self._evp_pkey, 103 ) 104 self._backend.openssl_assert(res == 1) 105 buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) 106 buflen = self._backend._ffi.new("size_t *", len(buf)) 107 res = self._backend._lib.EVP_DigestSign( 108 evp_md_ctx, buf, buflen, data, len(data) 109 ) 110 self._backend.openssl_assert(res == 1) 111 self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) 112 return self._backend._ffi.buffer(buf, buflen[0])[:] 113 114 def private_bytes(self, encoding, format, encryption_algorithm): 115 if ( 116 encoding is serialization.Encoding.Raw 117 or format is serialization.PublicFormat.Raw 118 ): 119 if ( 120 format is not serialization.PrivateFormat.Raw 121 or encoding is not serialization.Encoding.Raw 122 or not isinstance( 123 encryption_algorithm, serialization.NoEncryption 124 ) 125 ): 126 raise ValueError( 127 "When using Raw both encoding and format must be Raw " 128 "and encryption_algorithm must be NoEncryption()" 129 ) 130 131 return self._raw_private_bytes() 132 133 return self._backend._private_key_bytes( 134 encoding, format, encryption_algorithm, self, self._evp_pkey, None 135 ) 136 137 def _raw_private_bytes(self): 138 buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) 139 buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) 140 res = self._backend._lib.EVP_PKEY_get_raw_private_key( 141 self._evp_pkey, buf, buflen 142 ) 143 self._backend.openssl_assert(res == 1) 144 self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) 145 return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] 146