1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10
11 /**
12 @file camellia.c
13 Implementation by Tom St Denis of Elliptic Semiconductor
14 */
15
16 #include "tomcrypt_private.h"
17
18 #ifdef LTC_CAMELLIA
19
20 const struct ltc_cipher_descriptor camellia_desc = {
21 "camellia",
22 23,
23 16, 32, 16, 18,
24 &camellia_setup,
25 &camellia_ecb_encrypt,
26 &camellia_ecb_decrypt,
27 &camellia_test,
28 &camellia_done,
29 &camellia_keysize,
30 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
31 };
32
33 static const ulong32 SP1110[] = {
34 0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700, 0xc0c0c000, 0xe5e5e500,
35 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500, 0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100,
36 0x23232300, 0xefefef00, 0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
37 0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500, 0x92929200, 0xbdbdbd00,
38 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00, 0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00,
39 0x3e3e3e00, 0x30303000, 0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
40 0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700, 0x5d5d5d00, 0x3d3d3d00,
41 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600, 0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00,
42 0x8b8b8b00, 0x0d0d0d00, 0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
43 0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100, 0x84848400, 0x99999900,
44 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200, 0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500,
45 0x6d6d6d00, 0xb7b7b700, 0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
46 0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00, 0x11111100, 0x1c1c1c00,
47 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600, 0x53535300, 0x18181800, 0xf2f2f200, 0x22222200,
48 0xfefefe00, 0x44444400, 0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
49 0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00, 0x69696900, 0x50505000,
50 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00, 0xa1a1a100, 0x89898900, 0x62626200, 0x97979700,
51 0x54545400, 0x5b5b5b00, 0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
52 0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700, 0x75757500, 0xdbdbdb00,
53 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00, 0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400,
54 0x87878700, 0x5c5c5c00, 0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
55 0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00, 0xbfbfbf00, 0xe2e2e200,
56 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600, 0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00,
57 0x81818100, 0x96969600, 0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
58 0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00, 0xbcbcbc00, 0x8e8e8e00,
59 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600, 0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900,
60 0x78787800, 0x98989800, 0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
61 0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200, 0x8d8d8d00, 0xfafafa00,
62 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500, 0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00,
63 0x36363600, 0x49494900, 0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
64 0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900, 0x43434300, 0xc1c1c100,
65 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400, 0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00,
66 };
67
68 static const ulong32 SP0222[] = {
69 0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e, 0x00818181, 0x00cbcbcb,
70 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a, 0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282,
71 0x00464646, 0x00dfdfdf, 0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
72 0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca, 0x00252525, 0x007b7b7b,
73 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f, 0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d,
74 0x007c7c7c, 0x00606060, 0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
75 0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e, 0x00bababa, 0x007a7a7a,
76 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad, 0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a,
77 0x00171717, 0x001a1a1a, 0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
78 0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363, 0x00090909, 0x00333333,
79 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585, 0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a,
80 0x00dadada, 0x006f6f6f, 0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
81 0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636, 0x00222222, 0x00383838,
82 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c, 0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444,
83 0x00fdfdfd, 0x00888888, 0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
84 0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9, 0x00d2d2d2, 0x00a0a0a0,
85 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa, 0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f,
86 0x00a8a8a8, 0x00b6b6b6, 0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
87 0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef, 0x00eaeaea, 0x00b7b7b7,
88 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5, 0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929,
89 0x000f0f0f, 0x00b8b8b8, 0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
90 0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe, 0x007f7f7f, 0x00c5c5c5,
91 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c, 0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676,
92 0x00030303, 0x002d2d2d, 0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
93 0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc, 0x00797979, 0x001d1d1d,
94 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d, 0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2,
95 0x00f0f0f0, 0x00313131, 0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
96 0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545, 0x001b1b1b, 0x00f5f5f5,
97 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa, 0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414,
98 0x006c6c6c, 0x00929292, 0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
99 0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393, 0x00868686, 0x00838383,
100 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9, 0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d,
101 };
102
103 static const ulong32 SP3033[] = {
104 0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393, 0x60006060, 0xf200f2f2,
105 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a, 0x75007575, 0x06000606, 0x57005757, 0xa000a0a0,
106 0x91009191, 0xf700f7f7, 0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
107 0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2, 0x49004949, 0xde00dede,
108 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7, 0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767,
109 0x1f001f1f, 0x18001818, 0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
110 0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3, 0xae00aeae, 0x9e009e9e,
111 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b, 0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6,
112 0xc500c5c5, 0x86008686, 0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
113 0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8, 0x42004242, 0xcc00cccc,
114 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161, 0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282,
115 0xb600b6b6, 0xdb00dbdb, 0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
116 0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d, 0x88008888, 0x0e000e0e,
117 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b, 0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111,
118 0x7f007f7f, 0x22002222, 0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
119 0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e, 0xb400b4b4, 0x28002828,
120 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe, 0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb,
121 0x2a002a2a, 0xad00adad, 0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
122 0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb, 0xba00baba, 0xed00eded,
123 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d, 0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a,
124 0xc300c3c3, 0x2e002e2e, 0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
125 0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf, 0xdf00dfdf, 0x71007171,
126 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313, 0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d,
127 0xc000c0c0, 0x4b004b4b, 0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
128 0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737, 0x5e005e5e, 0x47004747,
129 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b, 0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac,
130 0x3c003c3c, 0x4c004c4c, 0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
131 0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151, 0xc600c6c6, 0x7d007d7d,
132 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa, 0x7c007c7c, 0x77007777, 0x56005656, 0x05000505,
133 0x1b001b1b, 0xa400a4a4, 0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
134 0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4, 0xa100a1a1, 0xe000e0e0,
135 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a, 0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f,
136 };
137
138 static const ulong32 SP4404[] = {
139 0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057, 0xeaea00ea, 0xaeae00ae,
140 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5, 0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092,
141 0x86860086, 0xafaf00af, 0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
142 0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a, 0x51510051, 0x6c6c006c,
143 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0, 0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084,
144 0xdfdf00df, 0xcbcb00cb, 0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
145 0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c, 0x53530053, 0xf2f200f2,
146 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a, 0x24240024, 0xe8e800e8, 0x60600060, 0x69690069,
147 0xaaaa00aa, 0xa0a000a0, 0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
148 0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6, 0x09090009, 0xdddd00dd,
149 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090, 0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf,
150 0x52520052, 0xd8d800d8, 0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
151 0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9, 0x2f2f002f, 0xb4b400b4,
152 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071, 0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d,
153 0x72720072, 0xb9b900b9, 0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
154 0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad, 0x77770077, 0x80800080,
155 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5, 0x85850085, 0x35350035, 0x0c0c000c, 0x41410041,
156 0xefef00ef, 0x93930093, 0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
157 0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f, 0xc5c500c5, 0x1a1a001a,
158 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d, 0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d,
159 0x0d0d000d, 0x66660066, 0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
160 0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031, 0x17170017, 0xd7d700d7,
161 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c, 0x0f0f000f, 0x16160016, 0x18180018, 0x22220022,
162 0x44440044, 0xb2b200b2, 0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
163 0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095, 0xffff00ff, 0xd2d200d2,
164 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db, 0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094,
165 0x5c5c005c, 0x02020002, 0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
166 0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b, 0xbebe00be, 0x2e2e002e,
167 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e, 0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059,
168 0x98980098, 0x6a6a006a, 0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
169 0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068, 0x38380038, 0xa4a400a4,
170 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1, 0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e,
171 };
172
173 static const ulong64 key_sigma[] = {
174 CONST64(0xA09E667F3BCC908B),
175 CONST64(0xB67AE8584CAA73B2),
176 CONST64(0xC6EF372FE94F82BE),
177 CONST64(0x54FF53A5F1D36F1C),
178 CONST64(0x10E527FADE682D1D),
179 CONST64(0xB05688C2B3E6C1FD)
180 };
181
F(ulong64 x)182 static ulong64 F(ulong64 x)
183 {
184 ulong32 D, U;
185
186 #define loc(i) ((8-i)*8)
187
188 D = SP1110[(x >> loc(8)) & 0xFF] ^ SP0222[(x >> loc(5)) & 0xFF] ^ SP3033[(x >> loc(6)) & 0xFF] ^ SP4404[(x >> loc(7)) & 0xFF];
189 U = SP1110[(x >> loc(1)) & 0xFF] ^ SP0222[(x >> loc(2)) & 0xFF] ^ SP3033[(x >> loc(3)) & 0xFF] ^ SP4404[(x >> loc(4)) & 0xFF];
190
191 D ^= U;
192 U = D ^ RORc(U, 8);
193
194 return ((ulong64)U) | (((ulong64)D) << CONST64(32));
195 }
196
rot_128(const unsigned char * in,unsigned count,unsigned char * out)197 static void rot_128(const unsigned char *in, unsigned count, unsigned char *out)
198 {
199 unsigned x, w, b;
200
201 w = count >> 3;
202 b = count & 7;
203
204 for (x = 0; x < 16; x++) {
205 out[x] = (in[(x+w)&15] << b) | (in[(x+w+1)&15] >> (8 - b));
206 }
207 }
208
camellia_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)209 int camellia_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
210 {
211 unsigned char T[48], kA[16], kB[16], kR[16], kL[16];
212 int x;
213 ulong64 A, B;
214
215 LTC_ARGCHK(key != NULL);
216 LTC_ARGCHK(skey != NULL);
217
218 /* Valid sizes (in bytes) are 16, 24, 32 */
219 if (keylen != 16 && keylen != 24 && keylen != 32) {
220 return CRYPT_INVALID_KEYSIZE;
221 }
222
223 /* number of rounds */
224 skey->camellia.R = (keylen == 16) ? 18 : 24;
225
226 if (num_rounds != 0 && num_rounds != skey->camellia.R) {
227 return CRYPT_INVALID_ROUNDS;
228 }
229
230 /* expand key */
231 if (keylen == 16) {
232 for (x = 0; x < 16; x++) {
233 T[x] = key[x];
234 T[x + 16] = 0;
235 }
236 } else if (keylen == 24) {
237 for (x = 0; x < 24; x++) {
238 T[x] = key[x];
239 }
240 for (x = 24; x < 32; x++) {
241 T[x] = key[x-8] ^ 0xFF;
242 }
243 } else {
244 for (x = 0; x < 32; x++) {
245 T[x] = key[x];
246 }
247 }
248
249 for (x = 0; x < 16; x++) {
250 kL[x] = T[x];
251 kR[x] = T[x + 16];
252 }
253
254 for (x = 32; x < 48; x++) {
255 T[x] = T[x - 32] ^ T[x - 16];
256 }
257
258 /* first two rounds */
259 LOAD64H(A, T+32); LOAD64H(B, T+40);
260 B ^= F(A ^ key_sigma[0]);
261 A ^= F(B ^ key_sigma[1]);
262 STORE64H(A, T+32); STORE64H(B, T+40);
263
264 /* xor kL in */
265 for (x = 0; x < 16; x++) { T[x+32] ^= kL[x]; }
266
267 /* next two rounds */
268 LOAD64H(A, T+32); LOAD64H(B, T+40);
269 B ^= F(A ^ key_sigma[2]);
270 A ^= F(B ^ key_sigma[3]);
271 STORE64H(A, T+32); STORE64H(B, T+40);
272
273 /* grab KA */
274 for (x = 0; x < 16; x++) { kA[x] = T[x+32]; }
275
276 /* xor kR in */
277 for (x = 0; x < 16; x++) { T[x+32] ^= kR[x]; }
278
279 if (keylen == 16) {
280 /* grab whitening keys kw1 and kw2 */
281 LOAD64H(skey->camellia.kw[0], kL);
282 LOAD64H(skey->camellia.kw[1], kL+8);
283
284 /* k1-k2 */
285 LOAD64H(skey->camellia.k[0], kA);
286 LOAD64H(skey->camellia.k[1], kA+8);
287
288 /* rotate kL by 15, k3/k4 */
289 rot_128(kL, 15, T+32);
290 LOAD64H(skey->camellia.k[2], T+32);
291 LOAD64H(skey->camellia.k[3], T+40);
292
293 /* rotate kA by 15, k5/k6 */
294 rot_128(kA, 15, T+32);
295 LOAD64H(skey->camellia.k[4], T+32);
296 LOAD64H(skey->camellia.k[5], T+40);
297
298 /* rotate kA by 30, kl1, kl2 */
299 rot_128(kA, 30, T+32);
300 LOAD64H(skey->camellia.kl[0], T+32);
301 LOAD64H(skey->camellia.kl[1], T+40);
302
303 /* rotate kL by 45, k7/k8 */
304 rot_128(kL, 45, T+32);
305 LOAD64H(skey->camellia.k[6], T+32);
306 LOAD64H(skey->camellia.k[7], T+40);
307
308 /* rotate kA by 45, k9/k10 */
309 rot_128(kA, 45, T+32);
310 LOAD64H(skey->camellia.k[8], T+32);
311 rot_128(kL, 60, T+32);
312 LOAD64H(skey->camellia.k[9], T+40);
313
314 /* rotate kA by 60, k11/k12 */
315 rot_128(kA, 60, T+32);
316 LOAD64H(skey->camellia.k[10], T+32);
317 LOAD64H(skey->camellia.k[11], T+40);
318
319 /* rotate kL by 77, kl3, kl4 */
320 rot_128(kL, 77, T+32);
321 LOAD64H(skey->camellia.kl[2], T+32);
322 LOAD64H(skey->camellia.kl[3], T+40);
323
324 /* rotate kL by 94, k13/k14 */
325 rot_128(kL, 94, T+32);
326 LOAD64H(skey->camellia.k[12], T+32);
327 LOAD64H(skey->camellia.k[13], T+40);
328
329 /* rotate kA by 94, k15/k16 */
330 rot_128(kA, 94, T+32);
331 LOAD64H(skey->camellia.k[14], T+32);
332 LOAD64H(skey->camellia.k[15], T+40);
333
334 /* rotate kL by 111, k17/k18 */
335 rot_128(kL, 111, T+32);
336 LOAD64H(skey->camellia.k[16], T+32);
337 LOAD64H(skey->camellia.k[17], T+40);
338
339 /* rotate kA by 111, kw3/kw4 */
340 rot_128(kA, 111, T+32);
341 LOAD64H(skey->camellia.kw[2], T+32);
342 LOAD64H(skey->camellia.kw[3], T+40);
343 } else {
344 /* last two rounds */
345 LOAD64H(A, T+32); LOAD64H(B, T+40);
346 B ^= F(A ^ key_sigma[4]);
347 A ^= F(B ^ key_sigma[5]);
348 STORE64H(A, T+32); STORE64H(B, T+40);
349
350 /* grab kB */
351 for (x = 0; x < 16; x++) { kB[x] = T[x+32]; }
352
353 /* kw1/2 from kL*/
354 LOAD64H(skey->camellia.kw[0], kL);
355 LOAD64H(skey->camellia.kw[1], kL+8);
356
357 /* k1/k2 = kB */
358 LOAD64H(skey->camellia.k[0], kB);
359 LOAD64H(skey->camellia.k[1], kB+8);
360
361 /* k3/k4 = kR by 15 */
362 rot_128(kR, 15, T+32);
363 LOAD64H(skey->camellia.k[2], T+32);
364 LOAD64H(skey->camellia.k[3], T+40);
365
366 /* k5/k7 = kA by 15 */
367 rot_128(kA, 15, T+32);
368 LOAD64H(skey->camellia.k[4], T+32);
369 LOAD64H(skey->camellia.k[5], T+40);
370
371 /* kl1/2 = kR by 30 */
372 rot_128(kR, 30, T+32);
373 LOAD64H(skey->camellia.kl[0], T+32);
374 LOAD64H(skey->camellia.kl[1], T+40);
375
376 /* k7/k8 = kB by 30 */
377 rot_128(kB, 30, T+32);
378 LOAD64H(skey->camellia.k[6], T+32);
379 LOAD64H(skey->camellia.k[7], T+40);
380
381 /* k9/k10 = kL by 45 */
382 rot_128(kL, 45, T+32);
383 LOAD64H(skey->camellia.k[8], T+32);
384 LOAD64H(skey->camellia.k[9], T+40);
385
386 /* k11/k12 = kA by 45 */
387 rot_128(kA, 45, T+32);
388 LOAD64H(skey->camellia.k[10], T+32);
389 LOAD64H(skey->camellia.k[11], T+40);
390
391 /* kl3/4 = kL by 60 */
392 rot_128(kL, 60, T+32);
393 LOAD64H(skey->camellia.kl[2], T+32);
394 LOAD64H(skey->camellia.kl[3], T+40);
395
396 /* k13/k14 = kR by 60 */
397 rot_128(kR, 60, T+32);
398 LOAD64H(skey->camellia.k[12], T+32);
399 LOAD64H(skey->camellia.k[13], T+40);
400
401 /* k15/k16 = kB by 15 */
402 rot_128(kB, 60, T+32);
403 LOAD64H(skey->camellia.k[14], T+32);
404 LOAD64H(skey->camellia.k[15], T+40);
405
406 /* k17/k18 = kL by 77 */
407 rot_128(kL, 77, T+32);
408 LOAD64H(skey->camellia.k[16], T+32);
409 LOAD64H(skey->camellia.k[17], T+40);
410
411 /* kl5/6 = kA by 77 */
412 rot_128(kA, 77, T+32);
413 LOAD64H(skey->camellia.kl[4], T+32);
414 LOAD64H(skey->camellia.kl[5], T+40);
415
416 /* k19/k20 = kR by 94 */
417 rot_128(kR, 94, T+32);
418 LOAD64H(skey->camellia.k[18], T+32);
419 LOAD64H(skey->camellia.k[19], T+40);
420
421 /* k21/k22 = kA by 94 */
422 rot_128(kA, 94, T+32);
423 LOAD64H(skey->camellia.k[20], T+32);
424 LOAD64H(skey->camellia.k[21], T+40);
425
426 /* k23/k24 = kL by 111 */
427 rot_128(kL, 111, T+32);
428 LOAD64H(skey->camellia.k[22], T+32);
429 LOAD64H(skey->camellia.k[23], T+40);
430
431 /* kw2/kw3 = kB by 111 */
432 rot_128(kB, 111, T+32);
433 LOAD64H(skey->camellia.kw[2], T+32);
434 LOAD64H(skey->camellia.kw[3], T+40);
435 }
436
437 return CRYPT_OK;
438 }
439
camellia_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)440 int camellia_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
441 {
442 ulong64 L, R;
443 ulong32 a, b;
444
445 LOAD64H(L, pt+0); LOAD64H(R, pt+8);
446 L ^= skey->camellia.kw[0];
447 R ^= skey->camellia.kw[1];
448
449 /* first 6 rounds */
450 R ^= F(L ^ skey->camellia.k[0]);
451 L ^= F(R ^ skey->camellia.k[1]);
452 R ^= F(L ^ skey->camellia.k[2]);
453 L ^= F(R ^ skey->camellia.k[3]);
454 R ^= F(L ^ skey->camellia.k[4]);
455 L ^= F(R ^ skey->camellia.k[5]);
456
457 /* FL */
458 a = (ulong32)(L >> 32);
459 b = (ulong32)(L & 0xFFFFFFFFUL);
460 b ^= ROL((a & (ulong32)(skey->camellia.kl[0] >> 32)), 1);
461 a ^= b | (skey->camellia.kl[0] & 0xFFFFFFFFU);
462 L = (((ulong64)a) << 32) | b;
463
464 /* FL^-1 */
465 a = (ulong32)(R >> 32);
466 b = (ulong32)(R & 0xFFFFFFFFUL);
467 a ^= b | (skey->camellia.kl[1] & 0xFFFFFFFFU);
468 b ^= ROL((a & (ulong32)(skey->camellia.kl[1] >> 32)), 1);
469 R = (((ulong64)a) << 32) | b;
470
471 /* second 6 rounds */
472 R ^= F(L ^ skey->camellia.k[6]);
473 L ^= F(R ^ skey->camellia.k[7]);
474 R ^= F(L ^ skey->camellia.k[8]);
475 L ^= F(R ^ skey->camellia.k[9]);
476 R ^= F(L ^ skey->camellia.k[10]);
477 L ^= F(R ^ skey->camellia.k[11]);
478
479 /* FL */
480 a = (ulong32)(L >> 32);
481 b = (ulong32)(L & 0xFFFFFFFFUL);
482 b ^= ROL((a & (ulong32)(skey->camellia.kl[2] >> 32)), 1);
483 a ^= b | (skey->camellia.kl[2] & 0xFFFFFFFFU);
484 L = (((ulong64)a) << 32) | b;
485
486 /* FL^-1 */
487 a = (ulong32)(R >> 32);
488 b = (ulong32)(R & 0xFFFFFFFFUL);
489 a ^= b | (skey->camellia.kl[3] & 0xFFFFFFFFU);
490 b ^= ROL((a & (ulong32)(skey->camellia.kl[3] >> 32)), 1);
491 R = (((ulong64)a) << 32) | b;
492
493 /* third 6 rounds */
494 R ^= F(L ^ skey->camellia.k[12]);
495 L ^= F(R ^ skey->camellia.k[13]);
496 R ^= F(L ^ skey->camellia.k[14]);
497 L ^= F(R ^ skey->camellia.k[15]);
498 R ^= F(L ^ skey->camellia.k[16]);
499 L ^= F(R ^ skey->camellia.k[17]);
500
501 /* next FL */
502 if (skey->camellia.R == 24) {
503 /* FL */
504 a = (ulong32)(L >> 32);
505 b = (ulong32)(L & 0xFFFFFFFFUL);
506 b ^= ROL((a & (ulong32)(skey->camellia.kl[4] >> 32)), 1);
507 a ^= b | (skey->camellia.kl[4] & 0xFFFFFFFFU);
508 L = (((ulong64)a) << 32) | b;
509
510 /* FL^-1 */
511 a = (ulong32)(R >> 32);
512 b = (ulong32)(R & 0xFFFFFFFFUL);
513 a ^= b | (skey->camellia.kl[5] & 0xFFFFFFFFU);
514 b ^= ROL((a & (ulong32)(skey->camellia.kl[5] >> 32)), 1);
515 R = (((ulong64)a) << 32) | b;
516
517 /* fourth 6 rounds */
518 R ^= F(L ^ skey->camellia.k[18]);
519 L ^= F(R ^ skey->camellia.k[19]);
520 R ^= F(L ^ skey->camellia.k[20]);
521 L ^= F(R ^ skey->camellia.k[21]);
522 R ^= F(L ^ skey->camellia.k[22]);
523 L ^= F(R ^ skey->camellia.k[23]);
524 }
525
526 L ^= skey->camellia.kw[3];
527 R ^= skey->camellia.kw[2];
528
529 STORE64H(R, ct+0); STORE64H(L, ct+8);
530
531 return CRYPT_OK;
532 }
533
camellia_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)534 int camellia_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
535 {
536 ulong64 L, R;
537 ulong32 a, b;
538
539 LOAD64H(R, ct+0); LOAD64H(L, ct+8);
540 L ^= skey->camellia.kw[3];
541 R ^= skey->camellia.kw[2];
542
543 /* next FL */
544 if (skey->camellia.R == 24) {
545 /* fourth 6 rounds */
546 L ^= F(R ^ skey->camellia.k[23]);
547 R ^= F(L ^ skey->camellia.k[22]);
548 L ^= F(R ^ skey->camellia.k[21]);
549 R ^= F(L ^ skey->camellia.k[20]);
550 L ^= F(R ^ skey->camellia.k[19]);
551 R ^= F(L ^ skey->camellia.k[18]);
552
553 /* FL */
554 a = (ulong32)(L >> 32);
555 b = (ulong32)(L & 0xFFFFFFFFUL);
556 a ^= b | (skey->camellia.kl[4] & 0xFFFFFFFFU);
557 b ^= ROL((a & (ulong32)(skey->camellia.kl[4] >> 32)), 1);
558 L = (((ulong64)a) << 32) | b;
559
560 /* FL^-1 */
561 a = (ulong32)(R >> 32);
562 b = (ulong32)(R & 0xFFFFFFFFUL);
563 b ^= ROL((a & (ulong32)(skey->camellia.kl[5] >> 32)), 1);
564 a ^= b | (skey->camellia.kl[5] & 0xFFFFFFFFU);
565 R = (((ulong64)a) << 32) | b;
566
567 }
568
569 /* third 6 rounds */
570 L ^= F(R ^ skey->camellia.k[17]);
571 R ^= F(L ^ skey->camellia.k[16]);
572 L ^= F(R ^ skey->camellia.k[15]);
573 R ^= F(L ^ skey->camellia.k[14]);
574 L ^= F(R ^ skey->camellia.k[13]);
575 R ^= F(L ^ skey->camellia.k[12]);
576
577 /* FL */
578 a = (ulong32)(L >> 32);
579 b = (ulong32)(L & 0xFFFFFFFFUL);
580 a ^= b | (skey->camellia.kl[2] & 0xFFFFFFFFU);
581 b ^= ROL((a & (ulong32)(skey->camellia.kl[2] >> 32)), 1);
582 L = (((ulong64)a) << 32) | b;
583
584 /* FL^-1 */
585 a = (ulong32)(R >> 32);
586 b = (ulong32)(R & 0xFFFFFFFFUL);
587 b ^= ROL((a & (ulong32)(skey->camellia.kl[3] >> 32)), 1);
588 a ^= b | (skey->camellia.kl[3] & 0xFFFFFFFFU);
589 R = (((ulong64)a) << 32) | b;
590
591 /* second 6 rounds */
592 L ^= F(R ^ skey->camellia.k[11]);
593 R ^= F(L ^ skey->camellia.k[10]);
594 L ^= F(R ^ skey->camellia.k[9]);
595 R ^= F(L ^ skey->camellia.k[8]);
596 L ^= F(R ^ skey->camellia.k[7]);
597 R ^= F(L ^ skey->camellia.k[6]);
598
599 /* FL */
600 a = (ulong32)(L >> 32);
601 b = (ulong32)(L & 0xFFFFFFFFUL);
602 a ^= b | (skey->camellia.kl[0] & 0xFFFFFFFFU);
603 b ^= ROL((a & (ulong32)(skey->camellia.kl[0] >> 32)), 1);
604 L = (((ulong64)a) << 32) | b;
605
606 /* FL^-1 */
607 a = (ulong32)(R >> 32);
608 b = (ulong32)(R & 0xFFFFFFFFUL);
609 b ^= ROL((a & (ulong32)(skey->camellia.kl[1] >> 32)), 1);
610 a ^= b | (skey->camellia.kl[1] & 0xFFFFFFFFU);
611 R = (((ulong64)a) << 32) | b;
612
613 /* first 6 rounds */
614 L ^= F(R ^ skey->camellia.k[5]);
615 R ^= F(L ^ skey->camellia.k[4]);
616 L ^= F(R ^ skey->camellia.k[3]);
617 R ^= F(L ^ skey->camellia.k[2]);
618 L ^= F(R ^ skey->camellia.k[1]);
619 R ^= F(L ^ skey->camellia.k[0]);
620
621 R ^= skey->camellia.kw[1];
622 L ^= skey->camellia.kw[0];
623
624 STORE64H(R, pt+8); STORE64H(L, pt+0);
625
626 return CRYPT_OK;
627 }
628
camellia_test(void)629 int camellia_test(void)
630 {
631 static const struct {
632 int keylen;
633 unsigned char key[32], pt[16], ct[16];
634 } tests[] = {
635
636 {
637 16,
638 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
639 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
640 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
641 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
642 { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
643 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }
644 },
645
646 {
647 24,
648 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
649 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
650 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
651 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
652 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
653 { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
654 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }
655 },
656
657
658 {
659 32,
660 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
661 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
662 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
663 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
664 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
665 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
666 { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
667 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }
668 },
669
670 {
671 32,
672 { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE,
673 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81,
674 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7,
675 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 },
676 { 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
677 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 },
678 { 0x79, 0x60, 0x10, 0x9F, 0xB6, 0xDC, 0x42, 0x94,
679 0x7F, 0xCF, 0xE5, 0x9E, 0xA3, 0xC5, 0xEB, 0x6B }
680 }
681 };
682 unsigned char buf[2][16];
683 symmetric_key skey;
684 int err;
685 unsigned int x;
686
687 for (x = 0; x < sizeof(tests)/sizeof(tests[0]); x++) {
688 zeromem(&skey, sizeof(skey));
689 if ((err = camellia_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
690 return err;
691 }
692 if ((err = camellia_ecb_encrypt(tests[x].pt, buf[0], &skey)) != CRYPT_OK) {
693 camellia_done(&skey);
694 return err;
695 }
696 if ((err = camellia_ecb_decrypt(tests[x].ct, buf[1], &skey)) != CRYPT_OK) {
697 camellia_done(&skey);
698 return err;
699 }
700 camellia_done(&skey);
701 if (compare_testvector(tests[x].ct, 16, buf[0], 16, "Camellia Encrypt", x) ||
702 compare_testvector(tests[x].pt, 16, buf[1], 16, "Camellia Decrypt", x)) {
703 return CRYPT_FAIL_TESTVECTOR;
704 }
705 }
706 return CRYPT_OK;
707 }
708
camellia_done(symmetric_key * skey)709 void camellia_done(symmetric_key *skey)
710 {
711 LTC_UNUSED_PARAM(skey);
712 }
713
camellia_keysize(int * keysize)714 int camellia_keysize(int *keysize)
715 {
716 if (*keysize >= 32) { *keysize = 32; }
717 else if (*keysize >= 24) { *keysize = 24; }
718 else if (*keysize >= 16) { *keysize = 16; }
719 else return CRYPT_INVALID_KEYSIZE;
720 return CRYPT_OK;
721 }
722
723 #endif
724
725 /* ref: $Format:%D$ */
726 /* git commit: $Format:%H$ */
727 /* commit time: $Format:%ai$ */
728