int  fast_crypto_cipher_decrypt(struct crypto_cipher *ctx, const uint8_t *crypt,
			  uint8_t *plain, size_t len)
{
    size_t i, j, blocks;
    uint8_t tmp[32];
    struct fast_crypto_cipher *fast_ctx;

    fast_ctx = (struct fast_crypto_cipher *)ctx;
    
    switch (fast_ctx->alg) {
        case CRYPTO_CIPHER_ALG_RC4:
            if (plain != crypt) {
                os_memcpy(plain, crypt, len);
            }
            rc4_skip(fast_ctx->u.rc4.key, fast_ctx->u.rc4.keylen,
            fast_ctx->u.rc4.used_bytes, plain, len);
            fast_ctx->u.rc4.used_bytes += len;
            break;
        case CRYPTO_CIPHER_ALG_AES:
            if (len % AES_BLOCK_SIZE) {
                return -1;
            }
            blocks = len / AES_BLOCK_SIZE;
            for (i = 0; i < blocks; i++) {
                os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
                mbedtls_aes_decrypt(&(fast_ctx->u.aes.ctx_dec), crypt, plain);
                for (j = 0; j < AES_BLOCK_SIZE; j++)
                    plain[j] ^= fast_ctx->u.aes.cbc[j];
                os_memcpy(fast_ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
                plain += AES_BLOCK_SIZE;
                crypt += AES_BLOCK_SIZE;
            }
            break;
#ifdef CONFIG_DES3
        case CRYPTO_CIPHER_ALG_3DES:
            if (len % 8) {
                return -1;
            }
            blocks = len / 8;
            for (i = 0; i < blocks; i++) {
                os_memcpy(tmp, crypt, 8);
                des3_decrypt(crypt, &fast_ctx->u.des3.key, plain);
                for (j = 0; j < 8; j++) {
                    plain[j] ^= fast_ctx->u.des3.cbc[j];
                }
                os_memcpy(fast_ctx->u.des3.cbc, tmp, 8);
                plain += 8;
                crypt += 8;
            }
            break;
#endif
#ifdef CONFIG_DES
        case CRYPTO_CIPHER_ALG_DES:
            if (len % 8) {
                return -1;
            }
            blocks = len / 8;
            for (i = 0; i < blocks; i++) {
                os_memcpy(tmp, crypt, 8);
                des_block_decrypt(crypt, fast_ctx->u.des.dk, plain);
                for (j = 0; j < 8; j++) {
                    plain[j] ^= fast_ctx->u.des.cbc[j];
                }
                os_memcpy(fast_ctx->u.des.cbc, tmp, 8);
                plain += 8;
                crypt += 8;
            }
            break;
#endif
        default:
            return -1;
}

return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
			  u8 *plain, size_t len)
{
	size_t i, j, blocks;
	u8 tmp[32];

	switch (ctx->alg) {
	case CRYPTO_CIPHER_ALG_RC4:
		if (plain != crypt)
			os_memcpy(plain, crypt, len);
		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
			 ctx->u.rc4.used_bytes, plain, len);
		ctx->u.rc4.used_bytes += len;
		break;
	case CRYPTO_CIPHER_ALG_AES:
		if (len % AES_BLOCK_SIZE)
			return -1;
		blocks = len / AES_BLOCK_SIZE;
		for (i = 0; i < blocks; i++) {
			os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
			for (j = 0; j < AES_BLOCK_SIZE; j++)
				plain[j] ^= ctx->u.aes.cbc[j];
			os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
			plain += AES_BLOCK_SIZE;
			crypt += AES_BLOCK_SIZE;
		}
		break;
	case CRYPTO_CIPHER_ALG_3DES:
		if (len % 8)
			return -1;
		blocks = len / 8;
		for (i = 0; i < blocks; i++) {
			os_memcpy(tmp, crypt, 8);
			des3_decrypt(crypt, &ctx->u.des3.key, plain);
			for (j = 0; j < 8; j++)
				plain[j] ^= ctx->u.des3.cbc[j];
			os_memcpy(ctx->u.des3.cbc, tmp, 8);
			plain += 8;
			crypt += 8;
		}
		break;
	case CRYPTO_CIPHER_ALG_DES:
		if (len % 8)
			return -1;
		blocks = len / 8;
		for (i = 0; i < blocks; i++) {
			os_memcpy(tmp, crypt, 8);
			des_block_decrypt(crypt, ctx->u.des.dk, plain);
			for (j = 0; j < 8; j++)
				plain[j] ^= ctx->u.des.cbc[j];
			os_memcpy(ctx->u.des.cbc, tmp, 8);
			plain += 8;
			crypt += 8;
		}
		break;
	default:
		return -1;
	}

	return 0;
}