evp/e_camellia.c: engage SPARC T5 Camellia support [from master].
authorAndy Polyakov <appro@openssl.org>
Mon, 20 May 2013 14:09:13 +0000 (16:09 +0200)
committerAndy Polyakov <appro@openssl.org>
Mon, 20 May 2013 14:09:13 +0000 (16:09 +0200)
crypto/evp/e_camellia.c

index a7b40d1c6001065a34ca1a745c3678046a505689..1b758c73fc83faec5716e8bc2fd031851597b254 100644 (file)
@@ -61,6 +61,7 @@
 #include <assert.h>
 #include <openssl/camellia.h>
 #include "evp_locl.h"
+#include "modes_lcl.h"
 
 static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        const unsigned char *iv, int enc);
@@ -69,59 +70,336 @@ static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 typedef struct
        {
        CAMELLIA_KEY ks;
+       block128_f block;
+       union {
+               cbc128_f cbc;
+               ctr128_f ctr;
+       } stream;
        } EVP_CAMELLIA_KEY;
 
+#define MAXBITCHUNK    ((size_t)1<<(sizeof(size_t)*8-4))
+
 /* Attribute operation for Camellia */
 #define data(ctx)      EVP_C_DATA(EVP_CAMELLIA_KEY,ctx)
 
-IMPLEMENT_BLOCK_CIPHER(camellia_128, ks, Camellia, EVP_CAMELLIA_KEY,
-       NID_camellia_128, 16, 16, 16, 128,
-       0, camellia_init_key, NULL, 
-       EVP_CIPHER_set_asn1_iv,
-       EVP_CIPHER_get_asn1_iv,
-       NULL)
-IMPLEMENT_BLOCK_CIPHER(camellia_192, ks, Camellia, EVP_CAMELLIA_KEY,
-       NID_camellia_192, 16, 24, 16, 128,
-       0, camellia_init_key, NULL, 
-       EVP_CIPHER_set_asn1_iv,
-       EVP_CIPHER_get_asn1_iv,
-       NULL)
-IMPLEMENT_BLOCK_CIPHER(camellia_256, ks, Camellia, EVP_CAMELLIA_KEY,
-       NID_camellia_256, 16, 32, 16, 128,
-       0, camellia_init_key, NULL, 
-       EVP_CIPHER_set_asn1_iv,
-       EVP_CIPHER_get_asn1_iv,
-       NULL)
-
-#define IMPLEMENT_CAMELLIA_CFBR(ksize,cbits)   IMPLEMENT_CFBR(camellia,Camellia,EVP_CAMELLIA_KEY,ks,ksize,cbits,16)
-
-IMPLEMENT_CAMELLIA_CFBR(128,1)
-IMPLEMENT_CAMELLIA_CFBR(192,1)
-IMPLEMENT_CAMELLIA_CFBR(256,1)
-
-IMPLEMENT_CAMELLIA_CFBR(128,8)
-IMPLEMENT_CAMELLIA_CFBR(192,8)
-IMPLEMENT_CAMELLIA_CFBR(256,8)
+#if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
+/* ---------^^^ this is not a typo, just a way to detect that
+ * assembler support was in general requested... */
+#include "sparc_arch.h"
+
+extern unsigned int OPENSSL_sparcv9cap_P[];
+
+#define        SPARC_CMLL_CAPABLE      (OPENSSL_sparcv9cap_P[1] & CFR_CAMELLIA)
+
+void   cmll_t4_set_key (const unsigned char *key, int bits,
+                               CAMELLIA_KEY *ks);
+void   cmll_t4_encrypt (const unsigned char *in, unsigned char *out,
+                               const CAMELLIA_KEY *key);
+void   cmll_t4_decrypt (const unsigned char *in, unsigned char *out,
+                               const CAMELLIA_KEY *key);
+
+void   cmll128_t4_cbc_encrypt (const unsigned char *in, unsigned char *out,
+                               size_t len, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+void   cmll128_t4_cbc_decrypt (const unsigned char *in, unsigned char *out,
+                               size_t len, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+void   cmll256_t4_cbc_encrypt (const unsigned char *in, unsigned char *out,
+                               size_t len, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+void   cmll256_t4_cbc_decrypt (const unsigned char *in, unsigned char *out,
+                               size_t len, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+void   cmll128_t4_ctr32_encrypt (const unsigned char *in, unsigned char *out,
+                               size_t blocks, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+void   cmll256_t4_ctr32_encrypt (const unsigned char *in, unsigned char *out,
+                               size_t blocks, const CAMELLIA_KEY *key,
+                               unsigned char *ivec);
+
+static int cmll_t4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                  const unsigned char *iv, int enc)
+       {
+       int ret, mode, bits;
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       mode = ctx->cipher->flags & EVP_CIPH_MODE;
+       bits = ctx->key_len*8;
+
+       cmll_t4_set_key(key, bits, &dat->ks);
 
+       if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
+           && !enc)
+               {
+                   ret = 0;
+                   dat->block  = (block128_f)cmll_t4_decrypt;
+                   switch (bits) {
+                   case 128:
+                       dat->stream.cbc = mode==EVP_CIPH_CBC_MODE ?
+                                               (cbc128_f)cmll128_t4_cbc_decrypt :
+                                               NULL;
+                       break;
+                   case 192:
+                   case 256:
+                       dat->stream.cbc = mode==EVP_CIPH_CBC_MODE ?
+                                               (cbc128_f)cmll256_t4_cbc_decrypt :
+                                               NULL;
+                       break;
+                   default:
+                       ret = -1;
+                   }
+               }
+       else    {
+                   ret = 0;
+                   dat->block  = (block128_f)cmll_t4_encrypt;
+                   switch (bits) {
+                   case 128:
+                       if (mode==EVP_CIPH_CBC_MODE)
+                               dat->stream.cbc = (cbc128_f)cmll128_t4_cbc_encrypt;
+                       else if (mode==EVP_CIPH_CTR_MODE)
+                               dat->stream.ctr = (ctr128_f)cmll128_t4_ctr32_encrypt;
+                       else
+                               dat->stream.cbc = NULL;
+                       break;
+                   case 192:
+                   case 256:
+                       if (mode==EVP_CIPH_CBC_MODE)
+                               dat->stream.cbc = (cbc128_f)cmll256_t4_cbc_encrypt;
+                       else if (mode==EVP_CIPH_CTR_MODE)
+                               dat->stream.ctr = (ctr128_f)cmll256_t4_ctr32_encrypt;
+                       else
+                               dat->stream.cbc = NULL;
+                       break;
+                   default:
+                       ret = -1;
+                   }
+               }
 
+       if(ret < 0)
+               {
+               EVPerr(EVP_F_CMLL_T4_INIT_KEY,EVP_R_CAMELLIA_KEY_SETUP_FAILED);
+               return 0;
+               }
+
+       return 1;
+       }
+
+#define cmll_t4_cbc_cipher camellia_cbc_cipher
+static int cmll_t4_cbc_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len);
+
+#define cmll_t4_ecb_cipher camellia_ecb_cipher 
+static int cmll_t4_ecb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len);
+
+#define cmll_t4_ofb_cipher camellia_ofb_cipher
+static int cmll_t4_ofb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len);
+
+#define cmll_t4_cfb_cipher camellia_cfb_cipher
+static int cmll_t4_cfb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len);
+
+#define cmll_t4_cfb8_cipher camellia_cfb8_cipher
+static int cmll_t4_cfb8_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len);
+
+#define cmll_t4_cfb1_cipher camellia_cfb1_cipher
+static int cmll_t4_cfb1_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len);
+
+#define cmll_t4_ctr_cipher camellia_ctr_cipher
+static int cmll_t4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+               const unsigned char *in, size_t len);
+
+#define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
+static const EVP_CIPHER cmll_t4_##keylen##_##mode = { \
+       nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
+       flags|EVP_CIPH_##MODE##_MODE,   \
+       cmll_t4_init_key,               \
+       cmll_t4_##mode##_cipher,        \
+       NULL,                           \
+       sizeof(EVP_CAMELLIA_KEY),       \
+       NULL,NULL,NULL,NULL }; \
+static const EVP_CIPHER camellia_##keylen##_##mode = { \
+       nid##_##keylen##_##nmode,blocksize,     \
+       keylen/8,ivlen, \
+       flags|EVP_CIPH_##MODE##_MODE,   \
+       camellia_init_key,              \
+       camellia_##mode##_cipher,       \
+       NULL,                           \
+       sizeof(EVP_CAMELLIA_KEY),       \
+       NULL,NULL,NULL,NULL }; \
+const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
+{ return SPARC_CMLL_CAPABLE?&cmll_t4_##keylen##_##mode:&camellia_##keylen##_##mode; }
+
+#else
+
+#define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
+static const EVP_CIPHER camellia_##keylen##_##mode = { \
+       nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
+       flags|EVP_CIPH_##MODE##_MODE,   \
+       camellia_init_key,              \
+       camellia_##mode##_cipher,       \
+       NULL,                           \
+       sizeof(EVP_CAMELLIA_KEY),       \
+       NULL,NULL,NULL,NULL }; \
+const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
+{ return &camellia_##keylen##_##mode; }
+
+#endif
+
+#define BLOCK_CIPHER_generic_pack(nid,keylen,flags)            \
+       BLOCK_CIPHER_generic(nid,keylen,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)     \
+       BLOCK_CIPHER_generic(nid,keylen,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)      \
+       BLOCK_CIPHER_generic(nid,keylen,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
+       BLOCK_CIPHER_generic(nid,keylen,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)   \
+       BLOCK_CIPHER_generic(nid,keylen,1,16,cfb1,cfb1,CFB,flags)       \
+       BLOCK_CIPHER_generic(nid,keylen,1,16,cfb8,cfb8,CFB,flags)
+#if 0 /* not yet, missing NID */
+       BLOCK_CIPHER_generic(nid,keylen,1,16,ctr,ctr,CTR,flags)
+#endif
 
 /* The subkey for Camellia is generated. */ 
 static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        const unsigned char *iv, int enc)
        {
-       int ret;
-
-       ret=Camellia_set_key(key, ctx->key_len * 8, ctx->cipher_data);
+       int ret, mode;
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
 
+       ret=Camellia_set_key(key, ctx->key_len * 8, &dat->ks);
        if(ret < 0)
                {
                EVPerr(EVP_F_CAMELLIA_INIT_KEY,EVP_R_CAMELLIA_KEY_SETUP_FAILED);
                return 0;
                }
 
+       mode = ctx->cipher->flags & EVP_CIPH_MODE;
+       if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
+           && !enc)
+               {
+               dat->block      = (block128_f)Camellia_decrypt;
+               dat->stream.cbc = mode==EVP_CIPH_CBC_MODE ?
+                                       (cbc128_f)Camellia_cbc_encrypt :
+                                       NULL;
+               }
+       else
+               {
+               dat->block      = (block128_f)Camellia_encrypt;
+               dat->stream.cbc = mode==EVP_CIPH_CBC_MODE ?
+                                       (cbc128_f)Camellia_cbc_encrypt :
+                                       NULL;
+               }
+
+
        return 1;
        }
 
+static int camellia_cbc_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len)
+{
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       if (dat->stream.cbc)
+               (*dat->stream.cbc)(in,out,len,&dat->ks,ctx->iv,ctx->encrypt);
+       else if (ctx->encrypt)
+               CRYPTO_cbc128_encrypt(in,out,len,&dat->ks,ctx->iv,dat->block);
+       else
+               CRYPTO_cbc128_encrypt(in,out,len,&dat->ks,ctx->iv,dat->block);
+
+       return 1;
+}
+
+static int camellia_ecb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len)
+{
+       size_t  bl = ctx->cipher->block_size;
+       size_t  i;
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       if (len<bl)     return 1;
+
+       for (i=0,len-=bl;i<=len;i+=bl)
+               (*dat->block)(in+i,out+i,&dat->ks);
+
+       return 1;
+}
+
+static int camellia_ofb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       CRYPTO_ofb128_encrypt(in,out,len,&dat->ks,
+                       ctx->iv,&ctx->num,dat->block);
+       return 1;
+}
+
+static int camellia_cfb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       CRYPTO_cfb128_encrypt(in,out,len,&dat->ks,
+                       ctx->iv,&ctx->num,ctx->encrypt,dat->block);
+       return 1;
+}
+
+static int camellia_cfb8_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       CRYPTO_cfb128_8_encrypt(in,out,len,&dat->ks,
+                       ctx->iv,&ctx->num,ctx->encrypt,dat->block);
+       return 1;
+}
+
+static int camellia_cfb1_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       if (ctx->flags&EVP_CIPH_FLAG_LENGTH_BITS) {
+               CRYPTO_cfb128_1_encrypt(in,out,len,&dat->ks,
+                       ctx->iv,&ctx->num,ctx->encrypt,dat->block);
+               return 1;
+       }
+
+       while (len>=MAXBITCHUNK) {
+               CRYPTO_cfb128_1_encrypt(in,out,MAXBITCHUNK*8,&dat->ks,
+                       ctx->iv,&ctx->num,ctx->encrypt,dat->block);
+               len-=MAXBITCHUNK;
+       }
+       if (len)
+               CRYPTO_cfb128_1_encrypt(in,out,len*8,&dat->ks,
+                       ctx->iv,&ctx->num,ctx->encrypt,dat->block);
+       
+       return 1;
+}
+
+#if 0 /* not yet, missing NID */
+static int camellia_ctr_cipher (EVP_CIPHER_CTX *ctx, unsigned char *out,
+               const unsigned char *in, size_t len)
+{
+       unsigned int num = ctx->num;
+       EVP_CAMELLIA_KEY *dat = (EVP_CAMELLIA_KEY *)ctx->cipher_data;
+
+       if (dat->stream.ctr)
+               CRYPTO_ctr128_encrypt_ctr32(in,out,len,&dat->ks,
+                       ctx->iv,ctx->buf,&num,dat->stream.ctr);
+       else
+               CRYPTO_ctr128_encrypt(in,out,len,&dat->ks,
+                       ctx->iv,ctx->buf,&num,dat->block);
+       ctx->num = (size_t)num;
+       return 1;
+}
+#endif
+
+BLOCK_CIPHER_generic_pack(NID_camellia,128,0)
+BLOCK_CIPHER_generic_pack(NID_camellia,192,0)
+BLOCK_CIPHER_generic_pack(NID_camellia,256,0)
+
 #else
 
 # ifdef PEDANTIC