Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/aes.h')
-rw-r--r--crypto/aes.h160
1 files changed, 160 insertions, 0 deletions
diff --git a/crypto/aes.h b/crypto/aes.h
new file mode 100644
index 00000000..cab5b989
--- /dev/null
+++ b/crypto/aes.h
@@ -0,0 +1,160 @@
+/*
+ * Definitions likely to be helpful to multiple AES implementations.
+ */
+
+/*
+ * The 'extra' structure used by AES implementations is used to
+ * include information about how to check if a given implementation is
+ * available at run time, and whether we've already checked.
+ */
+struct aes_extra_mutable;
+struct aes_extra {
+ /* Function to check availability. Might be expensive, so we don't
+ * want to call it more than once. */
+ bool (*check_available)(void);
+
+ /* Point to a writable substructure. */
+ struct aes_extra_mutable *mut;
+
+ /* Extra API function specific to AES, to encrypt a single block
+ * in ECB mode without touching the IV. Used by AES-GCM MAC
+ * setup. */
+ void (*encrypt_ecb_block)(ssh_cipher *, void *);
+};
+struct aes_extra_mutable {
+ bool checked_availability;
+ bool is_available;
+};
+static inline bool check_availability(const struct aes_extra *extra)
+{
+ if (!extra->mut->checked_availability) {
+ extra->mut->is_available = extra->check_available();
+ extra->mut->checked_availability = true;
+ }
+
+ return extra->mut->is_available;
+}
+
+/* Shared stub function for all the AES-GCM vtables. */
+void aesgcm_cipher_crypt_length(
+ ssh_cipher *cipher, void *blk, int len, unsigned long seq);
+
+/* External entry point for the encrypt_ecb_block function. */
+static inline void aes_encrypt_ecb_block(ssh_cipher *ciph, void *blk)
+{
+ const struct aes_extra *extra = ciph->vt->extra;
+ extra->encrypt_ecb_block(ciph, blk);
+}
+
+/*
+ * Macros to define vtables for AES variants. There are a lot of
+ * these, because of the cross product between cipher modes, key
+ * sizes, and assorted HW/SW implementations, so it's worth spending
+ * some effort here to reduce the boilerplate in the sub-files.
+ */
+
+#define AES_EXTRA_BITS(impl_c, bits) \
+ static struct aes_extra_mutable aes ## impl_c ## _extra_mut; \
+ static const struct aes_extra aes ## bits ## impl_c ## _extra = { \
+ .check_available = aes ## impl_c ## _available, \
+ .mut = &aes ## impl_c ## _extra_mut, \
+ .encrypt_ecb_block = &aes ## bits ## impl_c ## _encrypt_ecb_block, \
+ }
+
+#define AES_EXTRA(impl_c) \
+ AES_EXTRA_BITS(impl_c, 128); \
+ AES_EXTRA_BITS(impl_c, 192); \
+ AES_EXTRA_BITS(impl_c, 256)
+
+#define AES_CBC_VTABLE(impl_c, impl_display, bits) \
+ const ssh_cipheralg ssh_aes ## bits ## _cbc ## impl_c = { \
+ .new = aes ## impl_c ## _new, \
+ .free = aes ## impl_c ## _free, \
+ .setiv = aes ## impl_c ## _setiv_cbc, \
+ .setkey = aes ## impl_c ## _setkey, \
+ .encrypt = aes ## bits ## impl_c ## _cbc_encrypt, \
+ .decrypt = aes ## bits ## impl_c ## _cbc_decrypt, \
+ .next_message = nullcipher_next_message, \
+ .ssh2_id = "aes" #bits "-cbc", \
+ .blksize = 16, \
+ .real_keybits = bits, \
+ .padded_keybytes = bits/8, \
+ .flags = SSH_CIPHER_IS_CBC, \
+ .text_name = "AES-" #bits " CBC (" impl_display ")", \
+ .extra = &aes ## bits ## impl_c ## _extra, \
+ }
+
+#define AES_SDCTR_VTABLE(impl_c, impl_display, bits) \
+ const ssh_cipheralg ssh_aes ## bits ## _sdctr ## impl_c = { \
+ .new = aes ## impl_c ## _new, \
+ .free = aes ## impl_c ## _free, \
+ .setiv = aes ## impl_c ## _setiv_sdctr, \
+ .setkey = aes ## impl_c ## _setkey, \
+ .encrypt = aes ## bits ## impl_c ## _sdctr, \
+ .decrypt = aes ## bits ## impl_c ## _sdctr, \
+ .next_message = nullcipher_next_message, \
+ .ssh2_id = "aes" #bits "-ctr", \
+ .blksize = 16, \
+ .real_keybits = bits, \
+ .padded_keybytes = bits/8, \
+ .flags = 0, \
+ .text_name = "AES-" #bits " SDCTR (" impl_display ")", \
+ .extra = &aes ## bits ## impl_c ## _extra, \
+ }
+
+#define AES_GCM_VTABLE(impl_c, impl_display, bits) \
+ const ssh_cipheralg ssh_aes ## bits ## _gcm ## impl_c = { \
+ .new = aes ## impl_c ## _new, \
+ .free = aes ## impl_c ## _free, \
+ .setiv = aes ## impl_c ## _setiv_gcm, \
+ .setkey = aes ## impl_c ## _setkey, \
+ .encrypt = aes ## bits ## impl_c ## _gcm, \
+ .decrypt = aes ## bits ## impl_c ## _gcm, \
+ .encrypt_length = aesgcm_cipher_crypt_length, \
+ .decrypt_length = aesgcm_cipher_crypt_length, \
+ .next_message = aes ## impl_c ## _next_message_gcm, \
+ /* 192-bit AES-GCM is included only so that testcrypt can run \
+ * standard test vectors against it. OpenSSH doesn't define a \
+ * protocol id for it. So we set its ssh2_id to NULL. */ \
+ .ssh2_id = bits==192 ? NULL : "aes" #bits "-gcm@openssh.com", \
+ .blksize = 16, \
+ .real_keybits = bits, \
+ .padded_keybytes = bits/8, \
+ .flags = SSH_CIPHER_SEPARATE_LENGTH, \
+ .text_name = "AES-" #bits " GCM (" impl_display ")", \
+ .required_mac = &ssh2_aesgcm_mac, \
+ .extra = &aes ## bits ## impl_c ## _extra, \
+ }
+
+#define AES_ALL_VTABLES(impl_c, impl_display) \
+ AES_CBC_VTABLE(impl_c, impl_display, 128); \
+ AES_CBC_VTABLE(impl_c, impl_display, 192); \
+ AES_CBC_VTABLE(impl_c, impl_display, 256); \
+ AES_SDCTR_VTABLE(impl_c, impl_display, 128); \
+ AES_SDCTR_VTABLE(impl_c, impl_display, 192); \
+ AES_SDCTR_VTABLE(impl_c, impl_display, 256); \
+ AES_GCM_VTABLE(impl_c, impl_display, 128); \
+ AES_GCM_VTABLE(impl_c, impl_display, 192); \
+ AES_GCM_VTABLE(impl_c, impl_display, 256)
+
+/*
+ * Macros to repeat a piece of code particular numbers of times that
+ * correspond to 1 fewer than the number of AES rounds. (Because the
+ * last round is different.)
+ */
+#define REP2(x) x x
+#define REP4(x) REP2(REP2(x))
+#define REP8(x) REP2(REP4(x))
+#define REP9(x) REP8(x) x
+#define REP11(x) REP8(x) REP2(x) x
+#define REP13(x) REP8(x) REP4(x) x
+
+/*
+ * The round constants used in key schedule expansion.
+ */
+extern const uint8_t aes_key_setup_round_constants[10];
+
+/*
+ * The largest number of round keys ever needed.
+ */
+#define MAXROUNDKEYS 15