2012-03-14 12:01:47

by Phil Sutter

[permalink] [raw]
Subject: Re: Problem with mv_cesa

Dear Mr. Goff,

(Adding linux-crypto in Cc, please always do so for this kind of
correspondence.)

On Tue, Mar 13, 2012 at 06:29:31PM +0000, Michael Goff wrote:
> I am running into an issue with mv_cesa. We are working with QNAP network attached storage devices that run a marvell arm chip that has crypto support via the mv_cesa module that you maintain. We are using the cryptodev module to run cryptography through the kernel from userspace. QNAP is running the linux kernel version 2.6.33.2. This version of mv_cesa seems to have a problem when hashing blocks larger than 1920 bytes. I noticed a commit (274252862f386b7868f35bf5ceaa5391a8ccfdf3) that says it fixes a 1920 byte limit and we also want to use the hardware offloading of sha1 provided by newer mv_cesa code. What we did is grab mv_cesa.c and mv_cesa.h (from 274252862f386b7868f35bf5ceaa5391a8ccfdf3) and built the mv_cesa module in the 2.6.33.2 tree. This seemed to have successfully added sha1 hardware offloading but rather than fixing the 1920 byte limit it made things worse.

I don't fully understand your description here. With vanilla 2.6.33.2
you say there is a problem with hashing blocks larger than 1920 bytes
although in vanilla 2.6.33.2 there was no support for sha1 in mv_cesa.c
yet?

> I am going to attach a simple c program that runs aes128 cbc through cryptodev and dumps the unencrypted and encrypted data in files. Then I run the unencrypted file through openssl to verify the results. Without the mv_cesa module insmoded the results of cryptodev and openssl are the same. With the mv_cesa module from 2.6.33.2, the results are the same up until after the 1920 byte limit. With the mv_cesa module built from 274252862f386b7868f35bf5ceaa5391a8ccfdf3 if the source data is all zeros the results are the same up until 1920, however if input data is anything other than all zeros (random or all 1's for instance) they differ completely.

Can you reproduce this with a current kernel? Just to make sure this is
not a heisenbug resulting from the combination of current mv_cesa.c with
your kernel version.

What hardware are you running this on exactly? Which implementation of
cryptodev are you using?

> The program I'm attaching to test this takes 3 parameters: the name of a file to place the data that will be encrypted, the name of a file to put the resulting encrypted data, the number of bytes of data to generate/encrypt. Here is a sample use of the program and comparing it to openssl:
> > gcc repro.c
> > ./a.out toencrypt cryptoenc 2000
> > openssl enc -in toencrypt -iv 0 -K 0 -out opensslenc -nopad -aes-128-cbc
> > hexdump -x cryptoenc > cryptoenc.hex
> > hexdump -x opensslenc > opensslenc.hex
> > diff cryptoenc.hex opensslenc.hex
>
> Here are the results of my tests again for reference:
> Setup
>
> Result
>
> Plain cryptodev without mv_cesa
>
> Works: same as openssl for tested values
>
> Mv_cesa from 2.6.33.2
>
> Works up to 1920 but after that different than openssl
>
> Mv_cesa from 274252862f386b7868f35bf5ceaa5391a8ccfdf3
>
> Works for all zeros input until 1920 then different but for all other input values differs from openssl output completely.
>
>
>
> Thank you for your help,
> Michael Goff
> Symform Inc.
> http://symform.com
>

> #include <stdio.h>
> #include <fcntl.h>
> #include <cryptodev.h>
> #include <string.h>
> #include <sys/ioctl.h>
>
> #define KEY_SIZE 16
> #define BLOCK_SIZE 16
>
> static int test_crypto(int fd, char *to_encrypt_file, char *encrypted_file, int data_size)
> {
> struct {
> char in[data_size],
> encrypted[data_size],
> iv[BLOCK_SIZE],
> key[KEY_SIZE];
> } data;
>
> struct session_op sess;
> struct crypt_op cryp;
>
> /* Set iv and key to 0's */
> memset(data.iv, 0, BLOCK_SIZE);
> memset(data.key, 0, KEY_SIZE);
>
> /* We'll leave data.in alone to pick up junk from the stack for "random" data */
>
> /* Get crypto session for AES128 */
> sess.cipher = CRYPTO_AES_CBC;
> sess.keylen = KEY_SIZE;
> sess.key = data.key;
> if (ioctl(fd, CIOCGSESSION, &sess)) {
> perror("ioctl(CIOCGSESSION)");
> return 1;
> }
>
> /* Encrypt data.in to data.encrypted */
> cryp.ses = sess.ses;
> cryp.len = sizeof(data.in);
> cryp.src = data.in;
> cryp.dst = data.encrypted;
> cryp.iv = data.iv;
> cryp.op = COP_ENCRYPT;
> if (ioctl(fd, CIOCCRYPT, &cryp)) {
> perror("ioctl(CIOCCRYPT)");
> return 1;
> }
>
> /* Output input and output of encryption */
> FILE *file = fopen(to_encrypt_file, "w+");
> fwrite(data.in, sizeof(char), data_size, file);
> fclose(file);
>
> file = fopen(encrypted_file, "w+");
> fwrite(data.encrypted, sizeof(char), data_size, file);
> fclose(file);
>
> /* Finish crypto session */
> if (ioctl(fd, CIOCFSESSION, &sess.ses)) {
> perror("ioctl(CIOCFSESSION)");
> return 1;
> }
>
> return 0;
> }
>
> int main(int argc, char *argv[])
> {
> if (argc != 4) {
> printf("Usage: %s UNENCRYPTED_FILE ENCRYPTED_FILE NUMBER_OF_BYTES", argv[0]);
> printf("\n\tUNENCRYPTED_FILE: Filename to write the input data used to");
> printf("\n\tENCRYPTED_FILE: File to write the encrypted input data to");
> printf("\n\tNUMBER_OF_BYTES: The number of bytes of data to encrypt");
> printf("\n\n\tThis program will take some data from stack garbage and encrypte it\n");
> printf("\n\toutputting the unencrypted and encrypted data to files.\n");
> printf("\n\tThen invoke openssl like the follow to verify:\n");
> printf("\n\topenssl enc -in UNENCRYPTED_FILE -iv 0 -K 0 \\\n");
> printf("\t\t-out OPENSSL_ENCRYPTED_FILE -nopad -aes-128-cbc\n");
> return 1;
> }
>
> int number_of_bytes = atoi(argv[3]);
>
> int fd = -1;
> fd = open("/dev/crypto", O_RDWR, 0);
> if (fd < 0)
> {
> perror("open(/dev/crypto)");
> return 1;
> }
>
> /* Set close-on-exec (not really neede here) */
> if (fcntl(fd, F_SETFD, 1) == -1) {
> perror("fcntl(F_SETFD)");
> return 1;
> }
>
> test_crypto(fd, argv[1], argv[2], number_of_bytes);
>
> if(close(fd))
> {
> perror("close(fd)");
> return 1;
> }
>
> return 0;
> }



Phil Sutter
Software Engineer

--
Viprinet – Never be offline again!

************************************************
Viprinet auf der CeBIT 2012 – 6.-10. März:
Besuchen Sie uns in Halle 13, Stand D27!
Alle gezeigten Produkte im Livebetrieb,
zahlreiche Beispielapplikationen. Gerne
schicken wir Ihnen kostenlose Eintrittskarten.
************************************************
Viprinet at CeBIT 2012, March 6 to 10
in Hannover, Germany. Come and visit us
at Hall 13, Booth D27! All exhibits shown
live, many sample applications. We’ll be
happy to send you free admission tickets.
************************************************


Viprinet GmbH
Mainzer Str. 43
55411 Bingen am Rhein
Germany

Phone/Zentrale: +49-6721-49030-0
Direct line/Durchwahl: +49-6721-49030-134
Fax: +49-6721-49030-209

[email protected]
http://www.viprinet.com

Registered office/Sitz der Gesellschaft: Bingen am Rhein
Commercial register/Handelsregister: Amtsgericht Mainz HRB40380
CEO/Geschäftsführer: Simon Kissel