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.ed448 import (
10    Ed448PrivateKey,
11    Ed448PublicKey,
12)
13
14_ED448_KEY_SIZE = 57
15_ED448_SIG_SIZE = 114
16
17
18@utils.register_interface(Ed448PublicKey)
19class _Ed448PublicKey(object):
20    def __init__(self, backend, evp_pkey):
21        self._backend = backend
22        self._evp_pkey = evp_pkey
23
24    def public_bytes(self, encoding, format):
25        if (
26            encoding is serialization.Encoding.Raw
27            or format is serialization.PublicFormat.Raw
28        ):
29            if (
30                encoding is not serialization.Encoding.Raw
31                or format is not serialization.PublicFormat.Raw
32            ):
33                raise ValueError(
34                    "When using Raw both encoding and format must be Raw"
35                )
36
37            return self._raw_public_bytes()
38
39        return self._backend._public_key_bytes(
40            encoding, format, self, self._evp_pkey, None
41        )
42
43    def _raw_public_bytes(self):
44        buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
45        buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
46        res = self._backend._lib.EVP_PKEY_get_raw_public_key(
47            self._evp_pkey, buf, buflen
48        )
49        self._backend.openssl_assert(res == 1)
50        self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
51        return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
52
53    def verify(self, signature, data):
54        evp_md_ctx = self._backend._lib.EVP_MD_CTX_new()
55        self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
56        evp_md_ctx = self._backend._ffi.gc(
57            evp_md_ctx, self._backend._lib.EVP_MD_CTX_free
58        )
59        res = self._backend._lib.EVP_DigestVerifyInit(
60            evp_md_ctx,
61            self._backend._ffi.NULL,
62            self._backend._ffi.NULL,
63            self._backend._ffi.NULL,
64            self._evp_pkey,
65        )
66        self._backend.openssl_assert(res == 1)
67        res = self._backend._lib.EVP_DigestVerify(
68            evp_md_ctx, signature, len(signature), data, len(data)
69        )
70        if res != 1:
71            self._backend._consume_errors()
72            raise exceptions.InvalidSignature
73
74
75@utils.register_interface(Ed448PrivateKey)
76class _Ed448PrivateKey(object):
77    def __init__(self, backend, evp_pkey):
78        self._backend = backend
79        self._evp_pkey = evp_pkey
80
81    def public_key(self):
82        buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
83        buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
84        res = self._backend._lib.EVP_PKEY_get_raw_public_key(
85            self._evp_pkey, buf, buflen
86        )
87        self._backend.openssl_assert(res == 1)
88        self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
89        public_bytes = self._backend._ffi.buffer(buf)[:]
90        return self._backend.ed448_load_public_bytes(public_bytes)
91
92    def sign(self, data):
93        evp_md_ctx = self._backend._lib.EVP_MD_CTX_new()
94        self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
95        evp_md_ctx = self._backend._ffi.gc(
96            evp_md_ctx, self._backend._lib.EVP_MD_CTX_free
97        )
98        res = self._backend._lib.EVP_DigestSignInit(
99            evp_md_ctx,
100            self._backend._ffi.NULL,
101            self._backend._ffi.NULL,
102            self._backend._ffi.NULL,
103            self._evp_pkey,
104        )
105        self._backend.openssl_assert(res == 1)
106        buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE)
107        buflen = self._backend._ffi.new("size_t *", len(buf))
108        res = self._backend._lib.EVP_DigestSign(
109            evp_md_ctx, buf, buflen, data, len(data)
110        )
111        self._backend.openssl_assert(res == 1)
112        self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE)
113        return self._backend._ffi.buffer(buf, buflen[0])[:]
114
115    def private_bytes(self, encoding, format, encryption_algorithm):
116        if (
117            encoding is serialization.Encoding.Raw
118            or format is serialization.PublicFormat.Raw
119        ):
120            if (
121                format is not serialization.PrivateFormat.Raw
122                or encoding is not serialization.Encoding.Raw
123                or not isinstance(
124                    encryption_algorithm, serialization.NoEncryption
125                )
126            ):
127                raise ValueError(
128                    "When using Raw both encoding and format must be Raw "
129                    "and encryption_algorithm must be NoEncryption()"
130                )
131
132            return self._raw_private_bytes()
133
134        return self._backend._private_key_bytes(
135            encoding, format, encryption_algorithm, self, self._evp_pkey, None
136        )
137
138    def _raw_private_bytes(self):
139        buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
140        buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
141        res = self._backend._lib.EVP_PKEY_get_raw_private_key(
142            self._evp_pkey, buf, buflen
143        )
144        self._backend.openssl_assert(res == 1)
145        self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
146        return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
147