1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier
45a913ee7SJerome Forissier /**
55a913ee7SJerome Forissier @file kasumi.c
65a913ee7SJerome Forissier Implementation of the 3GPP Kasumi block cipher
75a913ee7SJerome Forissier Derived from the 3GPP standard source code
85a913ee7SJerome Forissier */
95a913ee7SJerome Forissier
105a913ee7SJerome Forissier #include "tomcrypt_private.h"
115a913ee7SJerome Forissier
125a913ee7SJerome Forissier #ifdef LTC_KASUMI
135a913ee7SJerome Forissier
145a913ee7SJerome Forissier typedef unsigned u16;
155a913ee7SJerome Forissier
165a913ee7SJerome Forissier #define ROL16(x, y) ((((x)<<(y)) | ((x)>>(16-(y)))) & 0xFFFF)
175a913ee7SJerome Forissier
185a913ee7SJerome Forissier const struct ltc_cipher_descriptor kasumi_desc = {
195a913ee7SJerome Forissier "kasumi",
205a913ee7SJerome Forissier 21,
215a913ee7SJerome Forissier 16, 16, 8, 8,
225a913ee7SJerome Forissier &kasumi_setup,
235a913ee7SJerome Forissier &kasumi_ecb_encrypt,
245a913ee7SJerome Forissier &kasumi_ecb_decrypt,
255a913ee7SJerome Forissier &kasumi_test,
265a913ee7SJerome Forissier &kasumi_done,
275a913ee7SJerome Forissier &kasumi_keysize,
285a913ee7SJerome Forissier NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
295a913ee7SJerome Forissier };
305a913ee7SJerome Forissier
FI(u16 in,u16 subkey)315a913ee7SJerome Forissier static u16 FI( u16 in, u16 subkey )
325a913ee7SJerome Forissier {
335a913ee7SJerome Forissier u16 nine, seven;
345a913ee7SJerome Forissier static const u16 S7[128] = {
355a913ee7SJerome Forissier 54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18,123, 33,
365a913ee7SJerome Forissier 55,113, 39,114, 21, 67, 65, 12, 47, 73, 46, 27, 25,111,124, 81,
375a913ee7SJerome Forissier 53, 9,121, 79, 52, 60, 58, 48,101,127, 40,120,104, 70, 71, 43,
385a913ee7SJerome Forissier 20,122, 72, 61, 23,109, 13,100, 77, 1, 16, 7, 82, 10,105, 98,
395a913ee7SJerome Forissier 117,116, 76, 11, 89,106, 0,125,118, 99, 86, 69, 30, 57,126, 87,
405a913ee7SJerome Forissier 112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66,
415a913ee7SJerome Forissier 102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29,115, 44,
425a913ee7SJerome Forissier 64,107,108, 24,110, 83, 36, 78, 42, 19, 15, 41, 88,119, 59, 3 };
435a913ee7SJerome Forissier static const u16 S9[512] = {
445a913ee7SJerome Forissier 167,239,161,379,391,334, 9,338, 38,226, 48,358,452,385, 90,397,
455a913ee7SJerome Forissier 183,253,147,331,415,340, 51,362,306,500,262, 82,216,159,356,177,
465a913ee7SJerome Forissier 175,241,489, 37,206, 17, 0,333, 44,254,378, 58,143,220, 81,400,
475a913ee7SJerome Forissier 95, 3,315,245, 54,235,218,405,472,264,172,494,371,290,399, 76,
485a913ee7SJerome Forissier 165,197,395,121,257,480,423,212,240, 28,462,176,406,507,288,223,
495a913ee7SJerome Forissier 501,407,249,265, 89,186,221,428,164, 74,440,196,458,421,350,163,
505a913ee7SJerome Forissier 232,158,134,354, 13,250,491,142,191, 69,193,425,152,227,366,135,
515a913ee7SJerome Forissier 344,300,276,242,437,320,113,278, 11,243, 87,317, 36, 93,496, 27,
525a913ee7SJerome Forissier 487,446,482, 41, 68,156,457,131,326,403,339, 20, 39,115,442,124,
535a913ee7SJerome Forissier 475,384,508, 53,112,170,479,151,126,169, 73,268,279,321,168,364,
545a913ee7SJerome Forissier 363,292, 46,499,393,327,324, 24,456,267,157,460,488,426,309,229,
555a913ee7SJerome Forissier 439,506,208,271,349,401,434,236, 16,209,359, 52, 56,120,199,277,
565a913ee7SJerome Forissier 465,416,252,287,246, 6, 83,305,420,345,153,502, 65, 61,244,282,
575a913ee7SJerome Forissier 173,222,418, 67,386,368,261,101,476,291,195,430, 49, 79,166,330,
585a913ee7SJerome Forissier 280,383,373,128,382,408,155,495,367,388,274,107,459,417, 62,454,
595a913ee7SJerome Forissier 132,225,203,316,234, 14,301, 91,503,286,424,211,347,307,140,374,
605a913ee7SJerome Forissier 35,103,125,427, 19,214,453,146,498,314,444,230,256,329,198,285,
615a913ee7SJerome Forissier 50,116, 78,410, 10,205,510,171,231, 45,139,467, 29, 86,505, 32,
625a913ee7SJerome Forissier 72, 26,342,150,313,490,431,238,411,325,149,473, 40,119,174,355,
635a913ee7SJerome Forissier 185,233,389, 71,448,273,372, 55,110,178,322, 12,469,392,369,190,
645a913ee7SJerome Forissier 1,109,375,137,181, 88, 75,308,260,484, 98,272,370,275,412,111,
655a913ee7SJerome Forissier 336,318, 4,504,492,259,304, 77,337,435, 21,357,303,332,483, 18,
665a913ee7SJerome Forissier 47, 85, 25,497,474,289,100,269,296,478,270,106, 31,104,433, 84,
675a913ee7SJerome Forissier 414,486,394, 96, 99,154,511,148,413,361,409,255,162,215,302,201,
685a913ee7SJerome Forissier 266,351,343,144,441,365,108,298,251, 34,182,509,138,210,335,133,
695a913ee7SJerome Forissier 311,352,328,141,396,346,123,319,450,281,429,228,443,481, 92,404,
705a913ee7SJerome Forissier 485,422,248,297, 23,213,130,466, 22,217,283, 70,294,360,419,127,
715a913ee7SJerome Forissier 312,377, 7,468,194, 2,117,295,463,258,224,447,247,187, 80,398,
725a913ee7SJerome Forissier 284,353,105,390,299,471,470,184, 57,200,348, 63,204,188, 33,451,
735a913ee7SJerome Forissier 97, 30,310,219, 94,160,129,493, 64,179,263,102,189,207,114,402,
745a913ee7SJerome Forissier 438,477,387,122,192, 42,381, 5,145,118,180,449,293,323,136,380,
755a913ee7SJerome Forissier 43, 66, 60,455,341,445,202,432, 8,237, 15,376,436,464, 59,461};
765a913ee7SJerome Forissier
775a913ee7SJerome Forissier /* The sixteen bit input is split into two unequal halves, *
785a913ee7SJerome Forissier * nine bits and seven bits - as is the subkey */
795a913ee7SJerome Forissier
805a913ee7SJerome Forissier nine = (u16)(in>>7)&0x1FF;
815a913ee7SJerome Forissier seven = (u16)(in&0x7F);
825a913ee7SJerome Forissier
835a913ee7SJerome Forissier /* Now run the various operations */
845a913ee7SJerome Forissier nine = (u16)(S9[nine] ^ seven);
855a913ee7SJerome Forissier seven = (u16)(S7[seven] ^ (nine & 0x7F));
865a913ee7SJerome Forissier seven ^= (subkey>>9);
875a913ee7SJerome Forissier nine ^= (subkey&0x1FF);
885a913ee7SJerome Forissier nine = (u16)(S9[nine] ^ seven);
895a913ee7SJerome Forissier seven = (u16)(S7[seven] ^ (nine & 0x7F));
905a913ee7SJerome Forissier return (u16)(seven<<9) + nine;
915a913ee7SJerome Forissier }
925a913ee7SJerome Forissier
FO(ulong32 in,int round_no,const symmetric_key * key)935a913ee7SJerome Forissier static ulong32 FO( ulong32 in, int round_no, const symmetric_key *key)
945a913ee7SJerome Forissier {
955a913ee7SJerome Forissier u16 left, right;
965a913ee7SJerome Forissier
975a913ee7SJerome Forissier /* Split the input into two 16-bit words */
985a913ee7SJerome Forissier left = (u16)(in>>16);
995a913ee7SJerome Forissier right = (u16) in&0xFFFF;
1005a913ee7SJerome Forissier
1015a913ee7SJerome Forissier /* Now apply the same basic transformation three times */
1025a913ee7SJerome Forissier left ^= key->kasumi.KOi1[round_no];
1035a913ee7SJerome Forissier left = FI( left, key->kasumi.KIi1[round_no] );
1045a913ee7SJerome Forissier left ^= right;
1055a913ee7SJerome Forissier
1065a913ee7SJerome Forissier right ^= key->kasumi.KOi2[round_no];
1075a913ee7SJerome Forissier right = FI( right, key->kasumi.KIi2[round_no] );
1085a913ee7SJerome Forissier right ^= left;
1095a913ee7SJerome Forissier
1105a913ee7SJerome Forissier left ^= key->kasumi.KOi3[round_no];
1115a913ee7SJerome Forissier left = FI( left, key->kasumi.KIi3[round_no] );
1125a913ee7SJerome Forissier left ^= right;
1135a913ee7SJerome Forissier
1145a913ee7SJerome Forissier return (((ulong32)right)<<16)+left;
1155a913ee7SJerome Forissier }
1165a913ee7SJerome Forissier
FL(ulong32 in,int round_no,const symmetric_key * key)1175a913ee7SJerome Forissier static ulong32 FL( ulong32 in, int round_no, const symmetric_key *key )
1185a913ee7SJerome Forissier {
1195a913ee7SJerome Forissier u16 l, r, a, b;
1205a913ee7SJerome Forissier /* split out the left and right halves */
1215a913ee7SJerome Forissier l = (u16)(in>>16);
1225a913ee7SJerome Forissier r = (u16)(in)&0xFFFF;
1235a913ee7SJerome Forissier /* do the FL() operations */
1245a913ee7SJerome Forissier a = (u16) (l & key->kasumi.KLi1[round_no]);
1255a913ee7SJerome Forissier r ^= ROL16(a,1);
1265a913ee7SJerome Forissier b = (u16)(r | key->kasumi.KLi2[round_no]);
1275a913ee7SJerome Forissier l ^= ROL16(b,1);
1285a913ee7SJerome Forissier /* put the two halves back together */
1295a913ee7SJerome Forissier
1305a913ee7SJerome Forissier return (((ulong32)l)<<16) + r;
1315a913ee7SJerome Forissier }
1325a913ee7SJerome Forissier
kasumi_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)1335a913ee7SJerome Forissier int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
1345a913ee7SJerome Forissier {
1355a913ee7SJerome Forissier ulong32 left, right, temp;
1365a913ee7SJerome Forissier int n;
1375a913ee7SJerome Forissier
1385a913ee7SJerome Forissier LTC_ARGCHK(pt != NULL);
1395a913ee7SJerome Forissier LTC_ARGCHK(ct != NULL);
1405a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1415a913ee7SJerome Forissier
1425a913ee7SJerome Forissier LOAD32H(left, pt);
1435a913ee7SJerome Forissier LOAD32H(right, pt+4);
1445a913ee7SJerome Forissier
1455a913ee7SJerome Forissier for (n = 0; n <= 7; ) {
1465a913ee7SJerome Forissier temp = FL(left, n, skey);
1475a913ee7SJerome Forissier temp = FO(temp, n++, skey);
1485a913ee7SJerome Forissier right ^= temp;
1495a913ee7SJerome Forissier temp = FO(right, n, skey);
1505a913ee7SJerome Forissier temp = FL(temp, n++, skey);
1515a913ee7SJerome Forissier left ^= temp;
1525a913ee7SJerome Forissier }
1535a913ee7SJerome Forissier
1545a913ee7SJerome Forissier STORE32H(left, ct);
1555a913ee7SJerome Forissier STORE32H(right, ct+4);
1565a913ee7SJerome Forissier
1575a913ee7SJerome Forissier return CRYPT_OK;
1585a913ee7SJerome Forissier }
1595a913ee7SJerome Forissier
kasumi_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)1605a913ee7SJerome Forissier int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
1615a913ee7SJerome Forissier {
1625a913ee7SJerome Forissier ulong32 left, right, temp;
1635a913ee7SJerome Forissier int n;
1645a913ee7SJerome Forissier
1655a913ee7SJerome Forissier LTC_ARGCHK(pt != NULL);
1665a913ee7SJerome Forissier LTC_ARGCHK(ct != NULL);
1675a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1685a913ee7SJerome Forissier
1695a913ee7SJerome Forissier LOAD32H(left, ct);
1705a913ee7SJerome Forissier LOAD32H(right, ct+4);
1715a913ee7SJerome Forissier
1725a913ee7SJerome Forissier for (n = 7; n >= 0; ) {
1735a913ee7SJerome Forissier temp = FO(right, n, skey);
1745a913ee7SJerome Forissier temp = FL(temp, n--, skey);
1755a913ee7SJerome Forissier left ^= temp;
1765a913ee7SJerome Forissier temp = FL(left, n, skey);
1775a913ee7SJerome Forissier temp = FO(temp, n--, skey);
1785a913ee7SJerome Forissier right ^= temp;
1795a913ee7SJerome Forissier }
1805a913ee7SJerome Forissier
1815a913ee7SJerome Forissier STORE32H(left, pt);
1825a913ee7SJerome Forissier STORE32H(right, pt+4);
1835a913ee7SJerome Forissier
1845a913ee7SJerome Forissier return CRYPT_OK;
1855a913ee7SJerome Forissier }
1865a913ee7SJerome Forissier
kasumi_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)1875a913ee7SJerome Forissier int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
1885a913ee7SJerome Forissier {
1895a913ee7SJerome Forissier static const u16 C[8] = { 0x0123,0x4567,0x89AB,0xCDEF, 0xFEDC,0xBA98,0x7654,0x3210 };
1905a913ee7SJerome Forissier u16 ukey[8], Kprime[8];
1915a913ee7SJerome Forissier int n;
1925a913ee7SJerome Forissier
1935a913ee7SJerome Forissier LTC_ARGCHK(key != NULL);
1945a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1955a913ee7SJerome Forissier
1965a913ee7SJerome Forissier if (keylen != 16) {
1975a913ee7SJerome Forissier return CRYPT_INVALID_KEYSIZE;
1985a913ee7SJerome Forissier }
1995a913ee7SJerome Forissier
2005a913ee7SJerome Forissier if (num_rounds != 0 && num_rounds != 8) {
2015a913ee7SJerome Forissier return CRYPT_INVALID_ROUNDS;
2025a913ee7SJerome Forissier }
2035a913ee7SJerome Forissier
2045a913ee7SJerome Forissier /* Start by ensuring the subkeys are endian correct on a 16-bit basis */
2055a913ee7SJerome Forissier for (n = 0; n < 8; n++ ) {
2065a913ee7SJerome Forissier ukey[n] = (((u16)key[2*n]) << 8) | key[2*n+1];
2075a913ee7SJerome Forissier }
2085a913ee7SJerome Forissier
2095a913ee7SJerome Forissier /* Now build the K'[] keys */
2105a913ee7SJerome Forissier for (n = 0; n < 8; n++) {
2115a913ee7SJerome Forissier Kprime[n] = ukey[n] ^ C[n];
2125a913ee7SJerome Forissier }
2135a913ee7SJerome Forissier
2145a913ee7SJerome Forissier /* Finally construct the various sub keys */
2155a913ee7SJerome Forissier for(n = 0; n < 8; n++) {
2165a913ee7SJerome Forissier skey->kasumi.KLi1[n] = ROL16(ukey[n],1);
2175a913ee7SJerome Forissier skey->kasumi.KLi2[n] = Kprime[(n+2)&0x7];
2185a913ee7SJerome Forissier skey->kasumi.KOi1[n] = ROL16(ukey[(n+1)&0x7],5);
2195a913ee7SJerome Forissier skey->kasumi.KOi2[n] = ROL16(ukey[(n+5)&0x7],8);
2205a913ee7SJerome Forissier skey->kasumi.KOi3[n] = ROL16(ukey[(n+6)&0x7],13);
2215a913ee7SJerome Forissier skey->kasumi.KIi1[n] = Kprime[(n+4)&0x7];
2225a913ee7SJerome Forissier skey->kasumi.KIi2[n] = Kprime[(n+3)&0x7];
2235a913ee7SJerome Forissier skey->kasumi.KIi3[n] = Kprime[(n+7)&0x7];
2245a913ee7SJerome Forissier }
2255a913ee7SJerome Forissier
2265a913ee7SJerome Forissier return CRYPT_OK;
2275a913ee7SJerome Forissier }
2285a913ee7SJerome Forissier
kasumi_done(symmetric_key * skey)2295a913ee7SJerome Forissier void kasumi_done(symmetric_key *skey)
2305a913ee7SJerome Forissier {
2315a913ee7SJerome Forissier LTC_UNUSED_PARAM(skey);
2325a913ee7SJerome Forissier }
2335a913ee7SJerome Forissier
kasumi_keysize(int * keysize)2345a913ee7SJerome Forissier int kasumi_keysize(int *keysize)
2355a913ee7SJerome Forissier {
2365a913ee7SJerome Forissier LTC_ARGCHK(keysize != NULL);
2375a913ee7SJerome Forissier if (*keysize >= 16) {
2385a913ee7SJerome Forissier *keysize = 16;
2395a913ee7SJerome Forissier return CRYPT_OK;
2405a913ee7SJerome Forissier }
2415a913ee7SJerome Forissier return CRYPT_INVALID_KEYSIZE;
2425a913ee7SJerome Forissier }
2435a913ee7SJerome Forissier
kasumi_test(void)2445a913ee7SJerome Forissier int kasumi_test(void)
2455a913ee7SJerome Forissier {
2465a913ee7SJerome Forissier #ifndef LTC_TEST
2475a913ee7SJerome Forissier return CRYPT_NOP;
2485a913ee7SJerome Forissier #else
2495a913ee7SJerome Forissier static const struct {
2505a913ee7SJerome Forissier unsigned char key[16], pt[8], ct[8];
2515a913ee7SJerome Forissier } tests[] = {
2525a913ee7SJerome Forissier
2535a913ee7SJerome Forissier {
2545a913ee7SJerome Forissier { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2555a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2565a913ee7SJerome Forissier { 0x4B, 0x58, 0xA7, 0x71, 0xAF, 0xC7, 0xE5, 0xE8 }
2575a913ee7SJerome Forissier },
2585a913ee7SJerome Forissier
2595a913ee7SJerome Forissier {
2605a913ee7SJerome Forissier { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2615a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2625a913ee7SJerome Forissier { 0x7E, 0xEF, 0x11, 0x3C, 0x95, 0xBB, 0x5A, 0x77 }
2635a913ee7SJerome Forissier },
2645a913ee7SJerome Forissier
2655a913ee7SJerome Forissier {
2665a913ee7SJerome Forissier { 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2675a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2685a913ee7SJerome Forissier { 0x5F, 0x14, 0x06, 0x86, 0xD7, 0xAD, 0x5A, 0x39 },
2695a913ee7SJerome Forissier },
2705a913ee7SJerome Forissier
2715a913ee7SJerome Forissier {
2725a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
2735a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2745a913ee7SJerome Forissier { 0x2E, 0x14, 0x91, 0xCF, 0x70, 0xAA, 0x46, 0x5D }
2755a913ee7SJerome Forissier },
2765a913ee7SJerome Forissier
2775a913ee7SJerome Forissier {
2785a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 },
2795a913ee7SJerome Forissier { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2805a913ee7SJerome Forissier { 0xB5, 0x45, 0x86, 0xF4, 0xAB, 0x9A, 0xE5, 0x46 }
2815a913ee7SJerome Forissier },
2825a913ee7SJerome Forissier
2835a913ee7SJerome Forissier };
2845a913ee7SJerome Forissier unsigned char buf[2][8];
2855a913ee7SJerome Forissier symmetric_key key;
2865a913ee7SJerome Forissier int err, x;
2875a913ee7SJerome Forissier
2885a913ee7SJerome Forissier for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
2895a913ee7SJerome Forissier if ((err = kasumi_setup(tests[x].key, 16, 0, &key)) != CRYPT_OK) {
2905a913ee7SJerome Forissier return err;
2915a913ee7SJerome Forissier }
2925a913ee7SJerome Forissier if ((err = kasumi_ecb_encrypt(tests[x].pt, buf[0], &key)) != CRYPT_OK) {
2935a913ee7SJerome Forissier return err;
2945a913ee7SJerome Forissier }
2955a913ee7SJerome Forissier if ((err = kasumi_ecb_decrypt(tests[x].ct, buf[1], &key)) != CRYPT_OK) {
2965a913ee7SJerome Forissier return err;
2975a913ee7SJerome Forissier }
2985a913ee7SJerome Forissier if (compare_testvector(buf[1], 8, tests[x].pt, 8, "Kasumi Decrypt", x) ||
2995a913ee7SJerome Forissier compare_testvector(buf[0], 8, tests[x].ct, 8, "Kasumi Encrypt", x)) {
3005a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
3015a913ee7SJerome Forissier }
3025a913ee7SJerome Forissier }
3035a913ee7SJerome Forissier return CRYPT_OK;
3045a913ee7SJerome Forissier #endif
3055a913ee7SJerome Forissier }
3065a913ee7SJerome Forissier
3075a913ee7SJerome Forissier #endif
308