+
+ ctr_ctx = (gost_grasshopper_cipher_ctx_ctr *)
+ EVP_CIPHER_CTX_get_cipher_data(ctx);
+ c = &(ctr_ctx->c);
+
+ memcpy(seq, ptr, 8);
+ if (EVP_CIPHER_CTX_encrypting(ctx)) {
+ /*
+ * OpenSSL increments seq after mac calculation.
+ * As we have Mac-Then-Encrypt, we need decrement it here on encryption
+ * to derive the key correctly.
+ * */
+ if (memcmp(seq, zeroseq, 8) != 0)
+ {
+ for(j=7; j>=0; j--)
+ {
+ if (seq[j] != 0) {seq[j]--; break;}
+ else seq[j] = 0xFF;
+ }
+ }
+ }
+ if (gost_tlstree(NID_grasshopper_cbc, c->master_key.k.b, newkey,
+ (const unsigned char *)seq) > 0) {
+ memset(adjusted_iv, 0, 16);
+ memcpy(adjusted_iv, EVP_CIPHER_CTX_original_iv(ctx), 8);
+ for(j=7,carry=0; j>=0; j--)
+ {
+ int adj_byte = adjusted_iv[j]+seq[j]+carry;
+ carry = (adj_byte > 255) ? 1 : 0;
+ adjusted_iv[j] = adj_byte & 0xFF;
+ }
+ EVP_CIPHER_CTX_set_num(ctx, 0);
+ memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), adjusted_iv, 16);
+
+ gost_grasshopper_cipher_key(c, newkey);
+ return 1;
+ }
+ }
+ return -1;
+#endif
+#if 0
+ case EVP_CTRL_AEAD_GET_TAG:
+ case EVP_CTRL_AEAD_SET_TAG:
+ {
+ int taglen = arg;
+ unsigned char *tag = ptr;
+
+ gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
+ if (c->c.type != GRASSHOPPER_CIPHER_MGM)
+ return -1;
+
+ if (taglen > KUZNYECHIK_MAC_MAX_SIZE) {
+ CRYPTOCOMerr(CRYPTOCOM_F_GOST_GRASSHOPPER_CIPHER_CTL,
+ CRYPTOCOM_R_INVALID_TAG_LENGTH);
+ return -1;
+ }
+
+ if (type == EVP_CTRL_AEAD_GET_TAG)
+ memcpy(tag, c->final_tag, taglen);
+ else
+ memcpy(c->final_tag, tag, taglen);
+
+ return 1;
+ }
+#endif
+ case EVP_CTRL_PROCESS_UNPROTECTED:
+ {
+ gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
+ ASN1_OBJECT *cmsmacobj = NULL;
+ if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC)
+ return -1;
+ cmsmacobj = OBJ_txt2obj(OID_GOST_CMS_MAC, 1);
+ if (cmsmacobj == NULL) {
+ GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ if (arg == 0) /*Decrypting*/ {
+ STACK_OF(X509_ATTRIBUTE) *x = ptr;
+ ASN1_OCTET_STRING *osExpectedMac = X509at_get0_data_by_OBJ(x,
+ cmsmacobj, -3, V_ASN1_OCTET_STRING);
+ ASN1_OBJECT_free(cmsmacobj);
+
+ if (ptr == NULL || osExpectedMac ==NULL || osExpectedMac->length != KUZNYECHIK_MAC_MAX_SIZE)
+ return -1;
+
+ memcpy(c->tag, osExpectedMac->data, osExpectedMac->length);
+ return 1;
+ } else {
+ STACK_OF(X509_ATTRIBUTE) *x = ptr;
+ return (X509at_add1_attr_by_OBJ(&x, cmsmacobj,
+ V_ASN1_OCTET_STRING, c->tag, KUZNYECHIK_MAC_MAX_SIZE) == NULL) ? -1 : 1;
+ }
+ }
+ return 1;
+ case EVP_CTRL_COPY: {
+ EVP_CIPHER_CTX *out = ptr;
+
+ gost_grasshopper_cipher_ctx_ctr *out_cctx = EVP_CIPHER_CTX_get_cipher_data(out);
+ gost_grasshopper_cipher_ctx_ctr *in_cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+ if (in_cctx->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC)
+ return -1;
+
+ if (in_cctx->omac_ctx == out_cctx->omac_ctx) {
+ out_cctx->omac_ctx = EVP_MD_CTX_new();
+ if (out_cctx->omac_ctx == NULL) {
+ GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ }
+ return EVP_MD_CTX_copy(out_cctx->omac_ctx, in_cctx->omac_ctx);
+ }
+ default:
+ GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL,
+ GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
+ return -1;