Allow using IV and tags longer than the minimum lengths

This commit is contained in:
Kovid Goyal 2022-08-12 13:21:57 +05:30
parent 63fa0c4e94
commit da9ffc9b93
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 24 additions and 19 deletions

View File

@ -47,24 +47,25 @@ Encrypted communication
.. versionadded:: 0.26.0 .. versionadded:: 0.26.0
When using the :opt:`remote_control_password` option communication to the terminal is When using the :opt:`remote_control_password` option communication to the
encrypted to keep the password secure. A public key is used from the terminal is encrypted to keep the password secure. A public key is used from
:envvar:`KITTY_PUBLIC_KEY` environment variable. Currently, only one encryption the :envvar:`KITTY_PUBLIC_KEY` environment variable. Currently, only one
protocol is supported. The protocol number is present in encryption protocol is supported. The protocol number is present in
:envvar:`KITTY_PUBLIC_KEY` as ``1``. The key data in this environment variable is :envvar:`KITTY_PUBLIC_KEY` as ``1``. The key data in this environment variable
`Base-85 <https://github.com/git/git/blob/master/base85.c>`__ encoded. is `Base-85 <https://github.com/git/git/blob/master/base85.c>`__ encoded. The
The algorithm used is `Elliptic Curve Diffie Helman algorithm used is `Elliptic Curve Diffie Helman
<https://en.wikipedia.org/wiki/Elliptic-curve_DiffieHellman>`__ with the <https://en.wikipedia.org/wiki/Elliptic-curve_DiffieHellman>`__ with the
`X25519 curve <https://en.wikipedia.org/wiki/Curve25519>`__. A `X25519 curve <https://en.wikipedia.org/wiki/Curve25519>`__. A time based nonce
time based nonce is used to minimise replay attacks. The original JSON command has is used to minimise replay attacks. The original JSON command has the fields:
the fields: ``password`` and ``timestamp`` added. The timestamp is the number ``password`` and ``timestamp`` added. The timestamp is the number of
of nanoseconds since the epoch, excluding leap seconds. Commands with a nanoseconds since the epoch, excluding leap seconds. Commands with a timestamp
timestamp more than 5 minutes from the current time are rejected. The command is then more than 5 minutes from the current time are rejected. The command is then
encrypted using AES-256-GCM in authenticated encryption mode, with a symmetric key that encrypted using AES-256-GCM in authenticated encryption mode, with a symmetric
is derived from the ECDH key-pair by running the shared secret through SHA-256 hashing, once. key that is derived from the ECDH key-pair by running the shared secret through
An IV of 96 bits of CSPRNG data is used. The tag for authenticated encryption **must** be 128 bits long. SHA-256 hashing, once. An IV of at least 96 bits of CSPRNG data is used. The
The tag **must** authenticate only the value of the ``encrypted`` field. A new tag for authenticated encryption **must** be at least 128 bits long. The tag
command is created and transmitted that contains the fields: **must** authenticate only the value of the ``encrypted`` field. A new command
is created and transmitted that contains the fields:
.. code-block:: json .. code-block:: json

View File

@ -371,15 +371,19 @@ new_aes256gcmdecrypt(PyTypeObject *type, PyObject *args, PyObject *kwds UNUSED)
if (!PyArg_ParseTuple(args, "O!y#y#", &Secret_Type, &key, &iv, &iv_len, &tag, &tag_len)) return NULL; if (!PyArg_ParseTuple(args, "O!y#y#", &Secret_Type, &key, &iv, &iv_len, &tag, &tag_len)) return NULL;
const EVP_CIPHER *cipher = EVP_get_cipherbynid(NID_aes_256_gcm); const EVP_CIPHER *cipher = EVP_get_cipherbynid(NID_aes_256_gcm);
if (key->secret_len != (size_t)EVP_CIPHER_key_length(cipher)) { PyErr_Format(PyExc_ValueError, "The key for AES 256 GCM must be %d bytes long", EVP_CIPHER_key_length(cipher)); return NULL; } if (key->secret_len != (size_t)EVP_CIPHER_key_length(cipher)) { PyErr_Format(PyExc_ValueError, "The key for AES 256 GCM must be %d bytes long", EVP_CIPHER_key_length(cipher)); return NULL; }
if (iv_len != EVP_CIPHER_iv_length(cipher)) { PyErr_Format(PyExc_ValueError, "The iv for AES 256 GCM must be %d bytes long", EVP_CIPHER_iv_length(cipher)); return NULL; } if (iv_len < EVP_CIPHER_iv_length(cipher)) { PyErr_Format(PyExc_ValueError, "The iv for AES 256 GCM must be at least %d bytes long", EVP_CIPHER_iv_length(cipher)); return NULL; }
AES256GCMDecrypt *self = (AES256GCMDecrypt *)type->tp_alloc(type, 0); AES256GCMDecrypt *self = (AES256GCMDecrypt *)type->tp_alloc(type, 0);
if (!self) return NULL; if (!self) return NULL;
if (!(self->ctx = EVP_CIPHER_CTX_new())) { Py_CLEAR(self); return set_error_from_openssl("Failed to allocate decryption context"); } if (!(self->ctx = EVP_CIPHER_CTX_new())) { Py_CLEAR(self); return set_error_from_openssl("Failed to allocate decryption context"); }
if (iv_len > EVP_CIPHER_iv_length(cipher)) {
if (!EVP_CIPHER_CTX_ctrl(self->ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) { Py_CLEAR(self); return set_error_from_openssl("Failed to set the IV length"); }
}
if (1 != EVP_DecryptInit_ex(self->ctx, cipher, NULL, key->secret, iv)) { if (1 != EVP_DecryptInit_ex(self->ctx, cipher, NULL, key->secret, iv)) {
Py_CLEAR(self); return set_error_from_openssl("Failed to initialize encryption context"); } Py_CLEAR(self); return set_error_from_openssl("Failed to initialize encryption context"); }
// Ensure tag length is 16 because the OpenSSL verification routines will happily pass even if you set a truncated tag. // Ensure tag length is 16 because the OpenSSL verification routines will happily pass even if you set a truncated tag.
if (tag_len != cipher_ctx_tag_length(self->ctx)) { PyErr_Format(PyExc_ValueError, "Tag length for AES 256 GCM must be %d", cipher_ctx_tag_length(self->ctx)); return NULL; } if (tag_len < cipher_ctx_tag_length(self->ctx)) { PyErr_Format(PyExc_ValueError, "Tag length for AES 256 GCM must be at least %d", cipher_ctx_tag_length(self->ctx)); return NULL; }
if (!EVP_CIPHER_CTX_ctrl(self->ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag)) { Py_CLEAR(self); return set_error_from_openssl("Failed to set the tag"); } if (!EVP_CIPHER_CTX_ctrl(self->ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag)) { Py_CLEAR(self); return set_error_from_openssl("Failed to set the tag"); }
return (PyObject*)self; return (PyObject*)self;
} }