<enumerator name='GNUTLS_CIPHER_AES_256_CFB8' value='31'/>
<enumerator name='GNUTLS_CIPHER_AES_128_XTS' value='32'/>
<enumerator name='GNUTLS_CIPHER_AES_256_XTS' value='33'/>
+ <enumerator name='GNUTLS_CIPHER_GOST28147_TC26Z_CNT' value='34'/>
<enumerator name='GNUTLS_CIPHER_IDEA_PGP_CFB' value='200'/>
<enumerator name='GNUTLS_CIPHER_3DES_PGP_CFB' value='201'/>
<enumerator name='GNUTLS_CIPHER_CAST5_PGP_CFB' value='202'/>
.type = CIPHER_BLOCK,
.explicit_iv = 16,
.cipher_iv = 16},
+ { .name = "GOST28147-TC26Z-CNT",
+ .id = GNUTLS_CIPHER_GOST28147_TC26Z_CNT,
+ .blocksize = 8,
+ .keysize = 32,
+ .type = CIPHER_STREAM,
+ .implicit_iv = 8,
+ .cipher_iv = 8},
{ .name = "3DES-CBC",
.id = GNUTLS_CIPHER_3DES_CBC,
.blocksize = 8,
* The whole message needs to be provided with a single call, because
* cipher-stealing requires to know where the message actually terminates
* in order to be able to compute where the stealing occurs.
+ * @GNUTLS_CIPHER_GOST28147_TC26Z_CNT: GOST 28147-89 (Magma) cipher in CNT mode with TC26 Z S-box.
* @GNUTLS_CIPHER_IDEA_PGP_CFB: IDEA in CFB mode (placeholder - unsupported).
* @GNUTLS_CIPHER_3DES_PGP_CFB: 3DES in CFB mode (placeholder - unsupported).
* @GNUTLS_CIPHER_CAST5_PGP_CFB: CAST5 in CFB mode (placeholder - unsupported).
GNUTLS_CIPHER_AES_256_CFB8 = 31,
GNUTLS_CIPHER_AES_128_XTS = 32,
GNUTLS_CIPHER_AES_256_XTS = 33,
+ GNUTLS_CIPHER_GOST28147_TC26Z_CNT = 34,
/* used only for PGP internals. Ignored in TLS/SSL
*/
gost28147_set_key(ctx, key);
gost28147_set_param(ctx, &gost28147_param_CryptoPro_D);
}
+
+static void
+_gost28147_cnt_set_key_tc26z(void *ctx, const uint8_t *key)
+{
+ gost28147_cnt_init(ctx, key, &gost28147_param_TC26_Z);
+}
+
+static void
+_gost28147_cnt_set_nonce (void *ctx, size_t length, const uint8_t *nonce)
+{
+ gost28147_cnt_set_iv (ctx, nonce);
+}
+
+static void
+_gost28147_cnt_crypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
+ const uint8_t * src)
+{
+ gost28147_cnt_crypt((void *)ctx->ctx_ptr, length, dst, src);
+}
#endif
static void
.set_encrypt_key = _gost28147_set_key_cpd,
.set_decrypt_key = _gost28147_set_key_cpd,
},
+ {
+ .algo = GNUTLS_CIPHER_GOST28147_TC26Z_CNT,
+ .block_size = GOST28147_BLOCK_SIZE,
+ .key_size = GOST28147_KEY_SIZE,
+ .encrypt_block = (nettle_cipher_func*)gost28147_encrypt, /* unused */
+ .decrypt_block = (nettle_cipher_func*)gost28147_decrypt, /* unused */
+
+ .ctx_size = sizeof(struct gost28147_cnt_ctx),
+ .encrypt = _gost28147_cnt_crypt,
+ .decrypt = _gost28147_cnt_crypt,
+ .set_encrypt_key = _gost28147_cnt_set_key_tc26z,
+ .set_decrypt_key = _gost28147_cnt_set_key_tc26z,
+ .set_iv = (setiv_func)_gost28147_cnt_set_nonce,
+ },
#endif
{ .algo = GNUTLS_CIPHER_AES_128_CFB8,
.block_size = AES_BLOCK_SIZE,
ctx->key_count += GOST28147_BLOCK_SIZE;
}
}
+
+static void
+gost28147_cnt_next_iv(struct gost28147_cnt_ctx *ctx,
+ uint8_t *out)
+{
+ uint32_t block[2];
+ uint32_t temp;
+
+ if (ctx->ctx.key_meshing && ctx->ctx.key_count == 1024)
+ {
+ gost28147_key_mesh_cryptopro(&ctx->ctx);
+ gost28147_encrypt_simple(ctx->ctx.key, ctx->ctx.sbox, ctx->iv, ctx->iv);
+ ctx->ctx.key_count = 0;
+ }
+
+ ctx->iv[0] += 0x01010101;
+ temp = ctx->iv[1] + 0x01010104;
+ if (temp < ctx->iv[1])
+ ctx->iv[1] = temp + 1; /* Overflow */
+ else
+ ctx->iv[1] = temp;
+
+ gost28147_encrypt_simple(ctx->ctx.key, ctx->ctx.sbox, ctx->iv, block);
+
+ LE_WRITE_UINT32(out + 0, block[0]);
+ LE_WRITE_UINT32(out + 4, block[1]);
+
+ ctx->ctx.key_count += GOST28147_BLOCK_SIZE;
+}
+
+void
+gost28147_cnt_init(struct gost28147_cnt_ctx *ctx,
+ const uint8_t *key,
+ const struct gost28147_param *param)
+{
+ gost28147_set_key(&ctx->ctx, key);
+ gost28147_set_param(&ctx->ctx, param);
+ ctx->bytes = 0;
+}
+
+void
+gost28147_cnt_set_iv(struct gost28147_cnt_ctx *ctx,
+ const uint8_t *iv)
+{
+ uint32_t block[2];
+
+ block[0] = LE_READ_UINT32(iv + 0);
+ block[1] = LE_READ_UINT32(iv + 4);
+
+ gost28147_encrypt_simple(ctx->ctx.key, ctx->ctx.sbox, block, ctx->iv);
+}
+
+void
+gost28147_cnt_crypt(struct gost28147_cnt_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src)
+{
+ size_t block_size = GOST28147_BLOCK_SIZE;
+
+ if (ctx->bytes)
+ {
+ size_t part = ctx->bytes < length ? ctx->bytes : length;
+ memxor3(dst, src, ctx->buffer + block_size - ctx->bytes, part);
+ dst += part;
+ src += part;
+ length -= part;
+ ctx->bytes -= part;
+ ctx->bytes %= block_size;
+ }
+ while (length >= block_size)
+ {
+ gost28147_cnt_next_iv(ctx, ctx->buffer);
+ memxor3(dst, src, ctx->buffer, block_size);
+ length -= block_size;
+ src += block_size;
+ dst += block_size;
+ }
+
+ if (length != 0)
+ {
+ gost28147_cnt_next_iv(ctx, ctx->buffer);
+ memxor3(dst, src, ctx->buffer, length);
+ ctx->bytes = block_size - length;
+ }
+}
#endif
#define gost28147_encrypt_for_cfb _gnutls_gost28147_encrypt_for_cfb
#define gost28147_decrypt _gnutls_gost28147_decrypt
+#define gost28147_cnt_init _gnutls_gost28147_cnt_init
+#define gost28147_cnt_set_iv _gnutls_gost28147_cnt_set_iv
+#define gost28147_cnt_crypt _gnutls_gost28147_cnt_crypt
+
#define GOST28147_KEY_SIZE 32
#define GOST28147_BLOCK_SIZE 8
size_t length, uint8_t *dst,
const uint8_t *src);
+struct gost28147_cnt_ctx {
+ struct gost28147_ctx ctx;
+ size_t bytes;
+ uint32_t iv[2];
+ uint8_t buffer[GOST28147_BLOCK_SIZE];
+};
+
+void
+gost28147_cnt_init(struct gost28147_cnt_ctx *ctx,
+ const uint8_t *key,
+ const struct gost28147_param *param);
+
+void
+gost28147_cnt_set_iv(struct gost28147_cnt_ctx *ctx,
+ const uint8_t *iv);
+
+void
+gost28147_cnt_crypt(struct gost28147_cnt_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
#ifdef __cplusplus
}
#endif