Search code examples
encryptionlinux-kernelcryptographyaes-gcm

GCM-AEAD support for ubuntu system running linux kernel-3.10


I am trying to implement a AEAD sample code for encryption Using GCM encryption. But I always get invalid argument error while setting the key

static int init_aead(void)
    {
        printk("Starting encryption\n");
        struct crypto_aead *tfm = NULL;
        struct aead_request *req;
        struct tcrypt_result tresult;

        struct scatterlist plaintext[1] ;
        struct scatterlist ciphertext[1];
        struct scatterlist gmactext[1];
        unsigned char *plaindata = NULL;
        unsigned char *cipherdata = NULL;
        unsigned char *gmacdata = NULL;

        const u8 *key =  kmalloc(16, GFP_KERNEL);

        char *algo = "rfc4106(gcm(aes))";
        unsigned char *ivp = NULL;
        int ret, i, d;
        unsigned int iv_len;
        unsigned int keylen = 16;

        /* Allocating a cipher handle for AEAD */
        tfm = crypto_alloc_aead(algo, 0, 0);
        init_completion(&tresult.completion);
        if(IS_ERR(tfm)) {
                     pr_err("alg: aead: Failed to load transform for %s: %ld\n", algo,
                            PTR_ERR(tfm));
                return PTR_ERR(tfm);
        }

        /* Allocating request data structure to be used with AEAD data structure */
        req = aead_request_alloc(tfm, GFP_KERNEL);
        if(IS_ERR(req)) {
            pr_err("Couldn't allocate request handle for %s:\n", algo);
            return PTR_ERR(req);
        }

        /* Allocting a callback function to be used , when the request completes */
        aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, aead_work_done,&tresult);

        crypto_aead_clear_flags(tfm, ~0);

        /* Set key */
        get_random_bytes((void*)key, keylen);

     if((ret = crypto_aead_setkey(tfm, key, 16) != 0)) {
            pr_err("Return value for setkey is %d\n", ret);
            pr_info("key could not be set\n");
                ret = -EAGAIN;
            return ret;
        }

        /* Set authentication tag length */
            if(crypto_aead_setauthsize(tfm, 16)) {
            pr_info("Tag size could not be authenticated\n");
                ret = -EAGAIN;
            return ret;
        }

        /* Set IV size */
        iv_len = crypto_aead_ivsize(tfm);
        if (!(iv_len)){
            pr_info("IV size could not be authenticated\n");
                     ret = -EAGAIN;
                     return ret;
             }


        plaindata  = kmalloc(16, GFP_KERNEL);
        cipherdata = kmalloc(16, GFP_KERNEL);
        gmacdata   = kmalloc(16, GFP_KERNEL);
        ivp        = kmalloc(iv_len, GFP_KERNEL);

        if(!plaindata || !cipherdata || !gmacdata || !ivp) {
            printk("Memory not availaible\n");
            ret = -ENOMEM;
            return ret;
        }
        for (i = 0, d = 0; i < 16; i++, d++)
            plaindata[i] = d;

        memset(cipherdata, 0, 16);
        memset(gmacdata, 0, 16);

        for (i = 0,d=0xa8; i < 16; i++, d++)
            ivp[i] = d;

        sg_init_one(&plaintext[0], plaindata, 16);
        sg_init_one(&ciphertext[0], cipherdata, 16);
        sg_init_one(&gmactext[0], gmacdata, 128);
        aead_request_set_crypt(req, plaintext, ciphertext, 16, ivp);
        aead_request_set_assoc(req, gmactext, 16);

        ret = crypto_aead_encrypt(req);

        if (ret)
            printk("cipher call returns %d \n", ret);
        else
            printk("Failure \n");
        return 0;
     }

     module_init(init_aead);
     module_exit(exit_aead);
     MODULE_LICENSE("GPL");
     MODULE_DESCRIPTION("My code for aead encryption test");
     }

On inserting the module I get following output

Starting encryption
Return value for setkey is -22
key could not be set

According to AEAD specification aead uses aes-128 for encryption hence the block size should be 128 bit .

But my system shows only 1 Byte block size support for AEAD

name         : rfc4106(gcm(aes))
driver       : rfc4106-gcm-aesni
module       : aesni_intel
priority     : 400
refcnt       : 1
selftest     : passed
type         : nivaead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

Does the invalid argument error is thrown becuase of the block size. If so , what shall I do to make it work ?


Solution

  • The block size of AES is indeed always 128 bit. The block size of GCM is a different matter though. GCM (Galois-Counter Mode) is - as the name suggests - build on top of the CTR (Counter) mode of operation, sometimes also called the SIC (Segmented Integer Counter) mode of operation. This turns AES into a stream cipher. Stream ciphers - by definition - have a block size of one byte (or, more precisely, one bit, but bit level operations are usually not supported by API's).

    Block size however has little to do with the key size displayed in the call, and the argument does seem to require bytes instead of bits (in which key lengths are usually defined).

    The size of the IV should be 12 bytes (the default). Otherwise additional calculations may be needed by the GCM implementation (if those exist at all).