3

I'm trying to compute SHA1 of an integer array in the Linux kernel. I have gone through crypto.c/crypto.h and security/integrity/ima/ima_crypto.c but I can't figure out how to init and then update the SHA1 computer. Can someone point me to a tutorial or guide on how to go about doing this?

recluze
  • 1,920
  • 4
  • 21
  • 34

1 Answers1

10

There's a pretty good introduction to the linux cryptography api in Documentation/crypto/api-intro.txt. Also check out fs/ecryptfs/crypto.c for a real-life example of how the functions are used.

Here's a quick summary though to get you start:

Step 1: Declaration

Create some local variables:

struct scatterlist sg;
struct hash_desc desc;
char *plaintext = "plaintext goes here";
size_t len = strlen(plaintext);
u8 hashval[20];
  • A struct scatterlist is used to hold your plaintext in a format the crypto.h functions can understand, while a struct hash_desc is used to configure the hashing.
  • The variable plaintext holds our plaintext string, while hashval will hold the hash of our plaintext.
  • Finally, len holds the length the plaintext string.

Note that while I'm using ASCII plaintext in this example, you can pass an integer array as well -- just store the total memory size in len and replace every instance of plaintext with your integer array:

int myarr[4] = { 1, 3, 3, 7 };
size_t len = sizeof(myarr);

Be careful though: an int element generally has a size greater than a byte, so storing integer values in an int array won't have the same internal representation as a char array -- you may end up with null bytes as padding in between values.

Furthermore, if your intention is to hash the ASCII representation of your integers, you will have to first convert the values in your array to a string character sequence (perhaps using sprintf).

Step 2: Initialization

Initialize sg and desc:

sg_init_one(&sg, plaintext, len);
desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);

Notice that "sha1" is passed to crypto_alloc_hash; this can be set to "md5" for MD5 hashing, or any other supported string in order to use the respective hashing method.

Step 3: Hashing

Now perform the hashing with three function calls:

crypto_hash_init(&desc);
crypto_hash_update(&desc, &sg, len);
crypto_hash_final(&desc, hashval);
  • crypto_hash_init configures the hashing engine according to the supplied struct hash_desc.
  • crypto_hash_update performs the actual hashing method on the plaintext.
  • Finally, crypto_hash_final copies the hash to a character array.

Step 4: Cleanup

Free allocated memory held by desc.tfm:

crypto_free_hash(desc.tfm);

See also

how to use CryptoAPI in the linux kernel 2.6

Community
  • 1
  • 1
Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • Thanks a lot for the extremely detailed answer (as well as the customization). I will get to it as soon as possible and provide feedback. – recluze Jun 01 '13 at 04:34
  • 1
    I don't understand the rationale behind `sizeof(myarr) * sizeof(*myarr);`. `sizeof(myarr)` will give you 16 (assuming 32bit ints) and `sizeof(*myarr)` will give you 4. If you multiply them, it will give 64 which is definitely not the size of your array. – tangrs Jun 02 '13 at 01:54
  • @tangrs Oops, looks like I made an error (you only need `sizeof(myarr)`); I'll correct it in the answer. – Vilhelm Gray Jun 02 '13 at 13:39
  • The output of `crypto_hash_final()` is 20-byte binary, not hexadecimal ASCII, so the size of `hashtext` should be 20, not 41. – Wu Yongzheng Jan 07 '16 at 03:39
  • @WuYongzheng Thanks for catching that error; I've updated the answer now to reflect the correct 20-byte binary size. – Vilhelm Gray Jan 07 '16 at 13:31