├── images ├── RES_STAR.png ├── input.png.jpg ├── milenage1.png ├── milenage2.png └── wireshark-screenshot.png.jpg ├── src ├── rotate-bits │ ├── package.json │ └── rotate-bits.h ├── hmac-sha256.h ├── sha256.h ├── hmac-sha256.c ├── sha256.c └── milenage.cpp └── README.md /images/RES_STAR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimtangshfx/MilenageTest/HEAD/images/RES_STAR.png -------------------------------------------------------------------------------- /images/input.png.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimtangshfx/MilenageTest/HEAD/images/input.png.jpg -------------------------------------------------------------------------------- /images/milenage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimtangshfx/MilenageTest/HEAD/images/milenage1.png -------------------------------------------------------------------------------- /images/milenage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimtangshfx/MilenageTest/HEAD/images/milenage2.png -------------------------------------------------------------------------------- /images/wireshark-screenshot.png.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimtangshfx/MilenageTest/HEAD/images/wireshark-screenshot.png.jpg -------------------------------------------------------------------------------- /src/rotate-bits/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rotate-bits", 3 | "version": "0.1.1", 4 | "repo": "jb55/rotate-bits.h", 5 | "description": "rotate bits", 6 | "keywords": ["rotl", "rotr"], 7 | "src": ["rotate-bits.h"], 8 | "license": "Public Domain", 9 | "development": { 10 | "thlorenz/tap.c": "*" 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/hmac-sha256.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hmac-sha256.h 3 | * Copyright (C) 2017 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #ifndef HMAC_SHA256_H 9 | #define HMAC_SHA256_H 10 | 11 | #include 12 | #include 13 | 14 | #define HMAC_SHA256_DIGEST_SIZE 32 /* Same as SHA-256's output size. */ 15 | 16 | void 17 | hmac_sha256 (uint8_t out[HMAC_SHA256_DIGEST_SIZE], 18 | const uint8_t *data, size_t data_len, 19 | const uint8_t *key, size_t key_len); 20 | 21 | #endif /* !HMAC_SHA256_H */ 22 | -------------------------------------------------------------------------------- /src/sha256.h: -------------------------------------------------------------------------------- 1 | /* Sha256.h -- SHA-256 Hash 2 | 2010-06-11 : Igor Pavlov : Public domain */ 3 | 4 | #ifndef __CRYPTO_SHA256_H 5 | #define __CRYPTO_SHA256_H 6 | 7 | #include 8 | #include 9 | 10 | #define SHA256_DIGEST_SIZE 32 11 | 12 | typedef struct sha256_t 13 | { 14 | uint32_t state[8]; 15 | uint64_t count; 16 | unsigned char buffer[64]; 17 | } sha256_t; 18 | 19 | void sha256_init(sha256_t *p); 20 | void sha256_update(sha256_t *p, const unsigned char *data, size_t size); 21 | void sha256_final(sha256_t *p, unsigned char *digest); 22 | void sha256_hash(unsigned char *buf, const unsigned char *data, size_t size); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/rotate-bits/rotate-bits.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __ROTATE_DEFS_H 4 | #define __ROTATE_DEFS_H 5 | 6 | #ifdef _MSC_VER 7 | 8 | #include 9 | 10 | #define ROTL32(v, n) _rotl((v), (n)) 11 | #define ROTL64(v, n) _rotl64((v), (n)) 12 | 13 | #define ROTR32(v, n) _rotr((v), (n)) 14 | #define ROTR64(v, n) _rotr64((v), (n)) 15 | 16 | #else 17 | 18 | #include 19 | 20 | #define U8V(v) ((uint8_t)(v) & 0xFFU) 21 | #define U16V(v) ((uint16_t)(v) & 0xFFFFU) 22 | #define U32V(v) ((uint32_t)(v) & 0xFFFFFFFFU) 23 | #define U64V(v) ((uint64_t)(v) & 0xFFFFFFFFFFFFFFFFU) 24 | 25 | #define ROTL32(v, n) \ 26 | (U32V((uint32_t)(v) << (n)) | ((uint32_t)(v) >> (32 - (n)))) 27 | 28 | // tests fail if we don't have this cast... 29 | #define ROTL64(v, n) \ 30 | (U64V((uint64_t)(v) << (n)) | ((uint64_t)(v) >> (64 - (n)))) 31 | 32 | #define ROTR32(v, n) ROTL32(v, 32 - (n)) 33 | #define ROTR64(v, n) ROTL64(v, 64 - (n)) 34 | 35 | #endif 36 | 37 | #define ROTL8(v, n) \ 38 | (U8V((uint8_t)(v) << (n)) | ((uint8_t)(v) >> (8 - (n)))) 39 | 40 | #define ROTL16(v, n) \ 41 | (U16V((uint16_t)(v) << (n)) | ((uint16_t)(v) >> (16 - (n)))) 42 | 43 | #define ROTR8(v, n) ROTL8(v, 8 - (n)) 44 | #define ROTR16(v, n) ROTL16(v, 16 - (n)) 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/hmac-sha256.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hmac-sha256.c 3 | * Copyright (C) 2017 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | #include "hmac-sha256.h" 9 | #include "sha256.h" 10 | 11 | /* 12 | * HMAC(H, K) == H(K ^ opad, H(K ^ ipad, text)) 13 | * 14 | * H: Hash function (sha256) 15 | * K: Secret key 16 | * B: Block byte length 17 | * L: Byte length of hash function output 18 | * 19 | * https://tools.ietf.org/html/rfc2104 20 | */ 21 | 22 | #define B 64 23 | #define L (SHA256_DIGEST_SIZE) 24 | #define K (SHA256_DIGEST_SIZE * 2) 25 | 26 | #define I_PAD 0x36 27 | #define O_PAD 0x5C 28 | 29 | void 30 | hmac_sha256 (uint8_t out[HMAC_SHA256_DIGEST_SIZE], 31 | const uint8_t *data, size_t data_len, 32 | const uint8_t *key, size_t key_len) 33 | { 34 | 35 | sha256_t ss; 36 | uint8_t kh[SHA256_DIGEST_SIZE]; 37 | 38 | /* 39 | * If the key length is bigger than the buffer size B, apply the hash 40 | * function to it first and use the result instead. 41 | */ 42 | if (key_len > B) { 43 | sha256_init (&ss); 44 | sha256_update (&ss, key, key_len); 45 | sha256_final (&ss, kh); 46 | key_len = SHA256_DIGEST_SIZE; 47 | key = kh; 48 | } 49 | 50 | /* 51 | * (1) append zeros to the end of K to create a B byte string 52 | * (e.g., if K is of length 20 bytes and B=64, then K will be 53 | * appended with 44 zero bytes 0x00) 54 | * (2) XOR (bitwise exclusive-OR) the B byte string computed in step 55 | * (1) with ipad 56 | */ 57 | uint8_t kx[B]; 58 | for (size_t i = 0; i < key_len; i++) kx[i] = I_PAD ^ key[i]; 59 | for (size_t i = key_len; i < B; i++) kx[i] = I_PAD ^ 0; 60 | 61 | /* 62 | * (3) append the stream of data 'text' to the B byte string resulting 63 | * from step (2) 64 | * (4) apply H to the stream generated in step (3) 65 | */ 66 | sha256_init (&ss); 67 | sha256_update (&ss, kx, B); 68 | sha256_update (&ss, data, data_len); 69 | sha256_final (&ss, out); 70 | 71 | /* 72 | * (5) XOR (bitwise exclusive-OR) the B byte string computed in 73 | * step (1) with opad 74 | * 75 | * NOTE: The "kx" variable is reused. 76 | */ 77 | for (size_t i = 0; i < key_len; i++) kx[i] = O_PAD ^ key[i]; 78 | for (size_t i = key_len; i < B; i++) kx[i] = O_PAD ^ 0; 79 | 80 | /* 81 | * (6) append the H result from step (4) to the B byte string 82 | * resulting from step (5) 83 | * (7) apply H to the stream generated in step (6) and output 84 | * the result 85 | */ 86 | sha256_init (&ss); 87 | sha256_update (&ss, kx, B); 88 | sha256_update (&ss, out, SHA256_DIGEST_SIZE); 89 | sha256_final (&ss, out); 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MilenageTest 2 | ## A 3G/4G/5G authentication test troubleshooting tool written in c++ 3 | This small tool could be used to verify whether the MAC value or RES value exchanged during 3G/4G/5G authentication procude is correct or not. 4 | During my work in 3G/4G/5G authentication test and troubleshooting, there have been many cases that UE failed to pass the authentication procedure with core network. Usually it caused by mismatched secret key or OP settings, which results in "MAC failure" error or "RES value mismatched". In that case, we need a tool to verify that the MAC sent by core network or RES value sent by UE is correct, by computing those values based on secret key/OP/RAND value. 5 | So I came up with this idea to write a small tool in C, to manually compute the MAC/RES/RES* value and compare it to the one we received in authentication request and response message in pcap file, see whether it's matched. By that, we can tell which side is giving wrong computation result, and whether it's a potential problem of mismatched secret key/OP. 6 | # supported algorithm 7 | Milenage algorithm defined in 3GPP TS 35.206 for 3G/4G/5G MAC value calculation and 3G/4G RES value calculation. 8 | 9 | HMAC_SHA256 defined in 3GPP TS 33.501 for 5G RES* value calculation. 10 | # dependencies 11 | aperezdc/hmac-sha256: https://github.com/aperezdc/hmac-sha256 , HMAC-SHA256 implemented in C. 12 | 13 | The source code of milenage algorithm is from 3GPP TS 35.206 14 | 15 | The source code of HMAC-SHA256 is from https://github.com/aperezdc/hmac-sha256 16 | # how to compile: 17 | the milenage.cpp file uses raw string literal introduced in c++11 to print out source code on the fly, so please compile it using g++, for example: 18 | 19 | g++ -std=c++11 hmac-sha256.c sha256.c milenage.cpp -o output_file_name 20 | # how to use this tool: 21 | Simply compile the c code and run it, select the menu in below screenshot and let it compute the MAC and RES value (or compute RES* in 5G case) based on the secret key, OP, RAND, AUTN value you manually input. You need to have secret key of UE, OP value of network beforehand. Also need to get the RAND/AUTN value from authentication request message sent by AMF/MME/SGSN,you can do it usually by wireshark capture. 22 | 23 | below is the example: 24 | ![input](/images/input.png.jpg) 25 | compare it to the corresponding value in wireshark to verify it: 26 | ![wireshark-screen](/images/wireshark-screenshot.png.jpg) 27 | # the basic idea of how to compute the MAC/RES/RES* based on 3GPP spec: 28 | The main algorithm used by 3G/4G/5G authentication procedure is Milenage which is defined in 3GPP TS 35.205. 29 | It defines the f1/f2/f3/f4/f5 functions used to compute MAC/RES/CK/IK/AK , with sample source code attached in specification. 30 | So this tool uses the source from that spec to compute the MAC/RES based on the secret key(K) and OP,RAND input by user. 31 | Keys generated by milenage algorithm: 32 | ![milenage1](/images/milenage1.png) 33 | Defintion of f1/f2/f3/f4/f5 functions: 34 | ![milenage2](/images/milenage2.png) 35 | 36 | To compute 5G RES*, there is one additional algorithm HMAC_SHA256 needed, and the derivation function is defined in Annex A.4 of 3GPP TS 33.501 as below, the input is SNN,RAND,RES,CK||IK,and the KDF is HMAC_256. 37 | ![res](/images/RES_STAR.png) 38 | 39 | -------------------------------------------------------------------------------- /src/sha256.c: -------------------------------------------------------------------------------- 1 | /* Crypto/Sha256.c -- SHA-256 Hash 2 | 2010-06-11 : Igor Pavlov : Public domain 3 | This code is based on public domain code from Wei Dai's Crypto++ library. */ 4 | 5 | #include "rotate-bits/rotate-bits.h" 6 | #include "sha256.h" 7 | 8 | /* define it for speed optimization */ 9 | #define _SHA256_UNROLL 10 | #define _SHA256_UNROLL2 11 | 12 | void 13 | sha256_init(sha256_t *p) 14 | { 15 | p->state[0] = 0x6a09e667; 16 | p->state[1] = 0xbb67ae85; 17 | p->state[2] = 0x3c6ef372; 18 | p->state[3] = 0xa54ff53a; 19 | p->state[4] = 0x510e527f; 20 | p->state[5] = 0x9b05688c; 21 | p->state[6] = 0x1f83d9ab; 22 | p->state[7] = 0x5be0cd19; 23 | p->count = 0; 24 | } 25 | 26 | #define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x, 22)) 27 | #define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x, 25)) 28 | #define s0(x) (ROTR32(x, 7) ^ ROTR32(x,18) ^ (x >> 3)) 29 | #define s1(x) (ROTR32(x,17) ^ ROTR32(x,19) ^ (x >> 10)) 30 | 31 | #define blk0(i) (W[i] = data[i]) 32 | #define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) 33 | 34 | #define Ch(x,y,z) (z^(x&(y^z))) 35 | #define Maj(x,y,z) ((x&y)|(z&(x|y))) 36 | 37 | #define a(i) T[(0-(i))&7] 38 | #define b(i) T[(1-(i))&7] 39 | #define c(i) T[(2-(i))&7] 40 | #define d(i) T[(3-(i))&7] 41 | #define e(i) T[(4-(i))&7] 42 | #define f(i) T[(5-(i))&7] 43 | #define g(i) T[(6-(i))&7] 44 | #define h(i) T[(7-(i))&7] 45 | 46 | 47 | #ifdef _SHA256_UNROLL2 48 | 49 | #define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ 50 | d += h; h += S0(a) + Maj(a, b, c) 51 | 52 | #define RX_8(i) \ 53 | R(a,b,c,d,e,f,g,h, i); \ 54 | R(h,a,b,c,d,e,f,g, (i+1)); \ 55 | R(g,h,a,b,c,d,e,f, (i+2)); \ 56 | R(f,g,h,a,b,c,d,e, (i+3)); \ 57 | R(e,f,g,h,a,b,c,d, (i+4)); \ 58 | R(d,e,f,g,h,a,b,c, (i+5)); \ 59 | R(c,d,e,f,g,h,a,b, (i+6)); \ 60 | R(b,c,d,e,f,g,h,a, (i+7)) 61 | 62 | #else 63 | 64 | #define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ 65 | d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) 66 | 67 | #ifdef _SHA256_UNROLL 68 | 69 | #define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); 70 | 71 | #endif 72 | 73 | #endif 74 | 75 | static const uint32_t K[64] = { 76 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 77 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 78 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 79 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 80 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 81 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 82 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 83 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 84 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 85 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 86 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 87 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 88 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 89 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 90 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 91 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 92 | }; 93 | 94 | static void 95 | sha256_transform(uint32_t *state, const uint32_t *data) 96 | { 97 | uint32_t W[16]; 98 | unsigned j; 99 | #ifdef _SHA256_UNROLL2 100 | uint32_t a,b,c,d,e,f,g,h; 101 | a = state[0]; 102 | b = state[1]; 103 | c = state[2]; 104 | d = state[3]; 105 | e = state[4]; 106 | f = state[5]; 107 | g = state[6]; 108 | h = state[7]; 109 | #else 110 | uint32_t T[8]; 111 | for (j = 0; j < 8; j++) 112 | T[j] = state[j]; 113 | #endif 114 | 115 | for (j = 0; j < 64; j += 16) 116 | { 117 | #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) 118 | RX_8(0); RX_8(8); 119 | #else 120 | unsigned i; 121 | for (i = 0; i < 16; i++) { R(i); } 122 | #endif 123 | } 124 | 125 | #ifdef _SHA256_UNROLL2 126 | state[0] += a; 127 | state[1] += b; 128 | state[2] += c; 129 | state[3] += d; 130 | state[4] += e; 131 | state[5] += f; 132 | state[6] += g; 133 | state[7] += h; 134 | #else 135 | for (j = 0; j < 8; j++) 136 | state[j] += T[j]; 137 | #endif 138 | 139 | /* Wipe variables */ 140 | /* memset(W, 0, sizeof(W)); */ 141 | /* memset(T, 0, sizeof(T)); */ 142 | } 143 | 144 | #undef S0 145 | #undef S1 146 | #undef s0 147 | #undef s1 148 | 149 | static void 150 | sha256_write_byte_block(sha256_t *p) 151 | { 152 | uint32_t data32[16]; 153 | unsigned i; 154 | for (i = 0; i < 16; i++) 155 | data32[i] = 156 | ((uint32_t)(p->buffer[i * 4 ]) << 24) + 157 | ((uint32_t)(p->buffer[i * 4 + 1]) << 16) + 158 | ((uint32_t)(p->buffer[i * 4 + 2]) << 8) + 159 | ((uint32_t)(p->buffer[i * 4 + 3])); 160 | sha256_transform(p->state, data32); 161 | } 162 | 163 | 164 | void 165 | sha256_hash(unsigned char *buf, const unsigned char *data, size_t size) 166 | { 167 | sha256_t hash; 168 | sha256_init(&hash); 169 | sha256_update(&hash, data, size); 170 | sha256_final(&hash, buf); 171 | } 172 | 173 | 174 | void 175 | sha256_update(sha256_t *p, const unsigned char *data, size_t size) 176 | { 177 | uint32_t curBufferPos = (uint32_t)p->count & 0x3F; 178 | while (size > 0) 179 | { 180 | p->buffer[curBufferPos++] = *data++; 181 | p->count++; 182 | size--; 183 | if (curBufferPos == 64) 184 | { 185 | curBufferPos = 0; 186 | sha256_write_byte_block(p); 187 | } 188 | } 189 | } 190 | 191 | 192 | void 193 | sha256_final(sha256_t *p, unsigned char *digest) 194 | { 195 | uint64_t lenInBits = (p->count << 3); 196 | uint32_t curBufferPos = (uint32_t)p->count & 0x3F; 197 | unsigned i; 198 | p->buffer[curBufferPos++] = 0x80; 199 | while (curBufferPos != (64 - 8)) 200 | { 201 | curBufferPos &= 0x3F; 202 | if (curBufferPos == 0) 203 | sha256_write_byte_block(p); 204 | p->buffer[curBufferPos++] = 0; 205 | } 206 | for (i = 0; i < 8; i++) 207 | { 208 | p->buffer[curBufferPos++] = (unsigned char)(lenInBits >> 56); 209 | lenInBits <<= 8; 210 | } 211 | sha256_write_byte_block(p); 212 | 213 | for (i = 0; i < 8; i++) 214 | { 215 | *digest++ = (unsigned char)(p->state[i] >> 24); 216 | *digest++ = (unsigned char)(p->state[i] >> 16); 217 | *digest++ = (unsigned char)(p->state[i] >> 8); 218 | *digest++ = (unsigned char)(p->state[i]); 219 | } 220 | sha256_init(p); 221 | } 222 | -------------------------------------------------------------------------------- /src/milenage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "hmac-sha256.h" 8 | #include "sha256.h" 9 | 10 | using namespace std; 11 | /*------------------------------------------------------------------- 12 | * Example algorithms f1, f1*, f2, f3, f4, f5, f5* 13 | *------------------------------------------------------------------- 14 | * 15 | * A sample implementation of the example 3GPP authentication and 16 | * key agreement functions f1, f1*, f2, f3, f4, f5 and f5*. This is 17 | * a byte-oriented implementation of the functions, and of the block 18 | * cipher kernel function Rijndael. 19 | * 20 | * This has been coded for clarity, not necessarily for efficiency. 21 | * 22 | * The functions f2, f3, f4 and f5 share the same inputs and have 23 | * been coded together as a single function. f1, f1* and f5* are 24 | * all coded separately. 25 | * 26 | *-----------------------------------------------------------------*/ 27 | 28 | typedef unsigned char u8; 29 | 30 | 31 | /*--------- Operator Variant Algorithm Configuration Field --------*/ 32 | 33 | /*------- Insert your value of OP here -------*/ 34 | //u8 OP[16] = {0x63, 0xbf, 0xa5, 0x0e, 0xe6, 0x52, 0x33, 0x65, 35 | // 0xff, 0x14, 0xc1, 0xf4, 0x5f, 0x88, 0x73, 0x7d}; 36 | /*------- Insert your value of OP here -------*/ 37 | 38 | 39 | /*--------------------------- prototypes --------------------------*/ 40 | double time_diff(struct timeval x , struct timeval y); 41 | 42 | void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 43 | u8 mac_a[8] ); 44 | void f2345 ( u8 k[16], u8 rand[16], 45 | u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ); 46 | void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 47 | u8 mac_s[8] ); 48 | void f5star( u8 k[16], u8 rand[16], 49 | u8 ak[6] ); 50 | void ComputeOPc( u8 op_c[16] ); 51 | void RijndaelKeySchedule( u8 key[16] ); 52 | void RijndaelEncrypt( u8 input[16], u8 output[16] ); 53 | void print_code_mac_res(); 54 | void print_code_res_star(); 55 | void print_constant(); 56 | u8 k[16],rand_value[16],res[8],ck[16],ik[16],ak[6],mac_a[8], 57 | sqn[6],amf[2],sqn_xor_ak[6],OP[16],op_c[16],autn[16],mac_s[8], 58 | auts[14],retrieved_mac_a[8],retrieved_mac_s[8],sqnms_xor_ak[6],ak_star[6],sqnms[6] = {0}; 59 | bool use_opc = false; 60 | string full_network_name; 61 | 62 | double time_diff(struct timeval x , struct timeval y) 63 | { 64 | double x_ms , y_ms , diff; 65 | 66 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 67 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 68 | 69 | diff = (double)y_ms - (double)x_ms; 70 | 71 | return diff; 72 | } 73 | 74 | /*------------------------------------------------------------------- 75 | * Algorithm f1 76 | *------------------------------------------------------------------- 77 | * 78 | * Computes network authentication code MAC-A from key K, random 79 | * challenge RAND, sequence number SQN and authentication management 80 | * field AMF. 81 | * 82 | *-----------------------------------------------------------------*/ 83 | 84 | void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 85 | u8 mac_a[8] ) 86 | { 87 | //u8 op_c[16]={0xE5,0xE8,0xD2,0x0F,0xB3,0x84,0xE2,0x47,0xAC,0x7A,0xA3,0xDC,0x9F,0xA3,0xDC,0xCB}; 88 | 89 | //u8 op_c[16]={0x63,0xbf,0xa5,0x0e,0xe6,0x52,0x33,0x65,0xff,0x14,0xc1,0xf4,0x5f,0x88,0x73,0x7d}; 90 | u8 temp[16]; 91 | u8 in1[16]; 92 | u8 out1[16]; 93 | u8 rijndaelInput[16]; 94 | u8 i; 95 | 96 | RijndaelKeySchedule( k ); 97 | if (!use_opc){ 98 | ComputeOPc( op_c ); 99 | } 100 | 101 | for (i=0; i<16; i++) 102 | rijndaelInput[i] = rand[i] ^ op_c[i]; 103 | RijndaelEncrypt( rijndaelInput, temp ); 104 | 105 | for (i=0; i<6; i++) 106 | { 107 | in1[i] = sqn[i]; 108 | in1[i+8] = sqn[i]; 109 | } 110 | for (i=0; i<2; i++) 111 | { 112 | in1[i+6] = amf[i]; 113 | in1[i+14] = amf[i]; 114 | } 115 | 116 | /* XOR op_c and in1, rotate by r1=64, and XOR * 117 | * on the constant c1 (which is all zeroes) */ 118 | 119 | for (i=0; i<16; i++) 120 | rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; 121 | 122 | /* XOR on the value temp computed before */ 123 | 124 | for (i=0; i<16; i++) 125 | rijndaelInput[i] ^= temp[i]; 126 | 127 | RijndaelEncrypt( rijndaelInput, out1 ); 128 | for (i=0; i<16; i++) 129 | out1[i] ^= op_c[i]; 130 | 131 | for (i=0; i<8; i++) 132 | mac_a[i] = out1[i]; 133 | 134 | return; 135 | } /* end of function f1 */ 136 | 137 | 138 | 139 | /*------------------------------------------------------------------- 140 | * Algorithms f2-f5 141 | *------------------------------------------------------------------- 142 | * 143 | * Takes key K and random challenge RAND, and returns response RES, 144 | * confidentiality key CK, integrity key IK and anonymity key AK. 145 | * 146 | *-----------------------------------------------------------------*/ 147 | 148 | void f2345 ( u8 k[16], u8 rand[16], 149 | u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ) 150 | { 151 | //u8 op_c[16]={0xE5,0xE8,0xD2,0x0F,0xB3,0x84,0xE2,0x47,0xAC,0x7A,0xA3,0xDC,0x9F,0xA3,0xDC,0xCB}; 152 | //u8 op_c[16]={0x63,0xbf,0xa5,0x0e,0xe6,0x52,0x33,0x65,0xff,0x14,0xc1,0xf4,0x5f,0x88,0x73,0x7d}; 153 | //u8 op_c[16]; 154 | u8 temp[16]; 155 | u8 out[16]; 156 | u8 rijndaelInput[16]; 157 | u8 i; 158 | 159 | RijndaelKeySchedule( k ); 160 | 161 | if (!use_opc){ 162 | ComputeOPc( op_c ); 163 | } 164 | 165 | for (i=0; i<16; i++) 166 | rijndaelInput[i] = rand[i] ^ op_c[i]; 167 | RijndaelEncrypt( rijndaelInput, temp ); 168 | 169 | /* To obtain output block OUT2: XOR OPc and TEMP, * 170 | * rotate by r2=0, and XOR on the constant c2 (which * 171 | * is all zeroes except that the last bit is 1). */ 172 | 173 | for (i=0; i<16; i++) 174 | rijndaelInput[i] = temp[i] ^ op_c[i]; 175 | rijndaelInput[15] ^= 1; 176 | 177 | RijndaelEncrypt( rijndaelInput, out ); 178 | for (i=0; i<16; i++) 179 | out[i] ^= op_c[i]; 180 | 181 | for (i=0; i<8; i++) 182 | res[i] = out[i+8]; 183 | for (i=0; i<6; i++) 184 | ak[i] = out[i]; 185 | 186 | /* To obtain output block OUT3: XOR OPc and TEMP, * 187 | * rotate by r3=32, and XOR on the constant c3 (which * 188 | * is all zeroes except that the next to last bit is 1). */ 189 | 190 | for (i=0; i<16; i++) 191 | rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i]; 192 | rijndaelInput[15] ^= 2; 193 | 194 | RijndaelEncrypt( rijndaelInput, out ); 195 | for (i=0; i<16; i++) 196 | out[i] ^= op_c[i]; 197 | 198 | for (i=0; i<16; i++) 199 | ck[i] = out[i]; 200 | 201 | /* To obtain output block OUT4: XOR OPc and TEMP, * 202 | * rotate by r4=64, and XOR on the constant c4 (which * 203 | * is all zeroes except that the 2nd from last bit is 1). */ 204 | 205 | for (i=0; i<16; i++) 206 | rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i]; 207 | rijndaelInput[15] ^= 4; 208 | 209 | RijndaelEncrypt( rijndaelInput, out ); 210 | for (i=0; i<16; i++) 211 | out[i] ^= op_c[i]; 212 | 213 | for (i=0; i<16; i++) 214 | ik[i] = out[i]; 215 | 216 | return; 217 | } /* end of function f2345 */ 218 | 219 | 220 | /*------------------------------------------------------------------- 221 | * Algorithm f1* 222 | *------------------------------------------------------------------- 223 | * 224 | * Computes resynch authentication code MAC-S from key K, random 225 | * challenge RAND, sequence number SQN and authentication management 226 | * field AMF. 227 | * 228 | *-----------------------------------------------------------------*/ 229 | 230 | void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 231 | u8 mac_s[8] ) 232 | { 233 | 234 | u8 temp[16]; 235 | u8 in1[16]; 236 | u8 out1[16]; 237 | u8 rijndaelInput[16]; 238 | u8 i; 239 | 240 | RijndaelKeySchedule( k ); 241 | 242 | if (!use_opc){ 243 | ComputeOPc( op_c ); 244 | } 245 | 246 | for (i=0; i<16; i++) 247 | rijndaelInput[i] = rand[i] ^ op_c[i]; 248 | RijndaelEncrypt( rijndaelInput, temp ); 249 | 250 | for (i=0; i<6; i++) 251 | { 252 | in1[i] = sqn[i]; 253 | in1[i+8] = sqn[i]; 254 | } 255 | for (i=0; i<2; i++) 256 | { 257 | in1[i+6] = amf[i]; 258 | in1[i+14] = amf[i]; 259 | } 260 | 261 | /* XOR op_c and in1, rotate by r1=64, and XOR * 262 | * on the constant c1 (which is all zeroes) */ 263 | 264 | for (i=0; i<16; i++) 265 | rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; 266 | 267 | /* XOR on the value temp computed before */ 268 | 269 | for (i=0; i<16; i++) 270 | rijndaelInput[i] ^= temp[i]; 271 | 272 | RijndaelEncrypt( rijndaelInput, out1 ); 273 | for (i=0; i<16; i++) 274 | out1[i] ^= op_c[i]; 275 | 276 | for (i=0; i<8; i++) 277 | mac_s[i] = out1[i+8]; 278 | 279 | return; 280 | } /* end of function f1star */ 281 | 282 | 283 | /*------------------------------------------------------------------- 284 | * Algorithm f5* 285 | *------------------------------------------------------------------- 286 | * 287 | * Takes key K and random challenge RAND, and returns resynch 288 | * anonymity key AK. 289 | * 290 | *-----------------------------------------------------------------*/ 291 | 292 | void f5star( u8 k[16], u8 rand[16], 293 | u8 ak[6] ) 294 | { 295 | 296 | u8 temp[16]; 297 | u8 out[16]; 298 | u8 rijndaelInput[16]; 299 | u8 i; 300 | 301 | RijndaelKeySchedule( k ); 302 | 303 | if (!use_opc){ 304 | ComputeOPc( op_c ); 305 | } 306 | 307 | for (i=0; i<16; i++) 308 | rijndaelInput[i] = rand[i] ^ op_c[i]; 309 | RijndaelEncrypt( rijndaelInput, temp ); 310 | 311 | /* To obtain output block OUT5: XOR OPc and TEMP, * 312 | * rotate by r5=96, and XOR on the constant c5 (which * 313 | * is all zeroes except that the 3rd from last bit is 1). */ 314 | 315 | for (i=0; i<16; i++) 316 | rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i]; 317 | rijndaelInput[15] ^= 8; 318 | 319 | RijndaelEncrypt( rijndaelInput, out ); 320 | for (i=0; i<16; i++) 321 | out[i] ^= op_c[i]; 322 | 323 | for (i=0; i<6; i++) 324 | ak[i] = out[i]; 325 | 326 | return; 327 | } /* end of function f5star */ 328 | 329 | 330 | /*------------------------------------------------------------------- 331 | * Function to compute OPc from OP and K. Assumes key schedule has 332 | already been performed. 333 | *-----------------------------------------------------------------*/ 334 | 335 | void ComputeOPc( u8 op_c[16] ) 336 | { 337 | u8 i; 338 | 339 | RijndaelEncrypt( OP, op_c ); 340 | for (i=0; i<16; i++) 341 | op_c[i] ^= OP[i]; 342 | 343 | return; 344 | } /* end of function ComputeOPc */ 345 | 346 | 347 | 348 | /*-------------------- Rijndael round subkeys ---------------------*/ 349 | u8 roundKeys[11][4][4]; 350 | 351 | /*--------------------- Rijndael S box table ----------------------*/ 352 | u8 S[256] = { 353 | 99,124,119,123,242,107,111,197, 48, 1,103, 43,254,215,171,118, 354 | 202,130,201,125,250, 89, 71,240,173,212,162,175,156,164,114,192, 355 | 183,253,147, 38, 54, 63,247,204, 52,165,229,241,113,216, 49, 21, 356 | 4,199, 35,195, 24,150, 5,154, 7, 18,128,226,235, 39,178,117, 357 | 9,131, 44, 26, 27,110, 90,160, 82, 59,214,179, 41,227, 47,132, 358 | 83,209, 0,237, 32,252,177, 91,106,203,190, 57, 74, 76, 88,207, 359 | 208,239,170,251, 67, 77, 51,133, 69,249, 2,127, 80, 60,159,168, 360 | 81,163, 64,143,146,157, 56,245,188,182,218, 33, 16,255,243,210, 361 | 205, 12, 19,236, 95,151, 68, 23,196,167,126, 61,100, 93, 25,115, 362 | 96,129, 79,220, 34, 42,144,136, 70,238,184, 20,222, 94, 11,219, 363 | 224, 50, 58, 10, 73, 6, 36, 92,194,211,172, 98,145,149,228,121, 364 | 231,200, 55,109,141,213, 78,169,108, 86,244,234,101,122,174, 8, 365 | 186,120, 37, 46, 28,166,180,198,232,221,116, 31, 75,189,139,138, 366 | 112, 62,181,102, 72, 3,246, 14, 97, 53, 87,185,134,193, 29,158, 367 | 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 368 | 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22, 369 | }; 370 | 371 | /*------- This array does the multiplication by x in GF(2^8) ------*/ 372 | u8 Xtime[256] = { 373 | 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 374 | 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 375 | 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 376 | 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126, 377 | 128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, 378 | 160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190, 379 | 192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222, 380 | 224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254, 381 | 27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5, 382 | 59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37, 383 | 91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69, 384 | 123,121,127,125,115,113,119,117,107,105,111,109, 99, 97,103,101, 385 | 155,153,159,157,147,145,151,149,139,137,143,141,131,129,135,133, 386 | 187,185,191,189,179,177,183,181,171,169,175,173,163,161,167,165, 387 | 219,217,223,221,211,209,215,213,203,201,207,205,195,193,199,197, 388 | 251,249,255,253,243,241,247,245,235,233,239,237,227,225,231,229 389 | }; 390 | 391 | 392 | /*------------------------------------------------------------------- 393 | * Rijndael key schedule function. Takes 16-byte key and creates 394 | * all Rijndael's internal subkeys ready for encryption. 395 | *-----------------------------------------------------------------*/ 396 | 397 | void RijndaelKeySchedule( u8 key[16] ) 398 | { 399 | u8 roundConst; 400 | int i, j; 401 | 402 | /* first round key equals key */ 403 | for (i=0; i<16; i++) 404 | roundKeys[0][i & 0x03][i>>2] = key[i]; 405 | 406 | roundConst = 1; 407 | 408 | /* now calculate round keys */ 409 | for (i=1; i<11; i++) 410 | { 411 | roundKeys[i][0][0] = S[roundKeys[i-1][1][3]] 412 | ^ roundKeys[i-1][0][0] ^ roundConst; 413 | roundKeys[i][1][0] = S[roundKeys[i-1][2][3]] 414 | ^ roundKeys[i-1][1][0]; 415 | roundKeys[i][2][0] = S[roundKeys[i-1][3][3]] 416 | ^ roundKeys[i-1][2][0]; 417 | roundKeys[i][3][0] = S[roundKeys[i-1][0][3]] 418 | ^ roundKeys[i-1][3][0]; 419 | 420 | for (j=0; j<4; j++) 421 | { 422 | roundKeys[i][j][1] = roundKeys[i-1][j][1] ^ roundKeys[i][j][0]; 423 | roundKeys[i][j][2] = roundKeys[i-1][j][2] ^ roundKeys[i][j][1]; 424 | roundKeys[i][j][3] = roundKeys[i-1][j][3] ^ roundKeys[i][j][2]; 425 | } 426 | 427 | /* update round constant */ 428 | roundConst = Xtime[roundConst]; 429 | } 430 | 431 | return; 432 | } /* end of function RijndaelKeySchedule */ 433 | 434 | 435 | /* Round key addition function */ 436 | void KeyAdd(u8 state[4][4], u8 roundKeys[11][4][4], int round) 437 | { 438 | int i, j; 439 | 440 | for (i=0; i<4; i++) 441 | for (j=0; j<4; j++) 442 | state[i][j] ^= roundKeys[round][i][j]; 443 | 444 | return; 445 | } 446 | 447 | 448 | /* Byte substitution transformation */ 449 | int ByteSub(u8 state[4][4]) 450 | { 451 | int i, j; 452 | 453 | for (i=0; i<4; i++) 454 | for (j=0; j<4; j++) 455 | state[i][j] = S[state[i][j]]; 456 | 457 | return 0; 458 | } 459 | 460 | 461 | /* Row shift transformation */ 462 | void ShiftRow(u8 state[4][4]) 463 | { 464 | u8 temp; 465 | 466 | /* left rotate row 1 by 1 */ 467 | temp = state[1][0]; 468 | state[1][0] = state[1][1]; 469 | state[1][1] = state[1][2]; 470 | state[1][2] = state[1][3]; 471 | state[1][3] = temp; 472 | 473 | /* left rotate row 2 by 2 */ 474 | temp = state[2][0]; 475 | state[2][0] = state[2][2]; 476 | state[2][2] = temp; 477 | temp = state[2][1]; 478 | state[2][1] = state[2][3]; 479 | state[2][3] = temp; 480 | 481 | /* left rotate row 3 by 3 */ 482 | temp = state[3][0]; 483 | state[3][0] = state[3][3]; 484 | state[3][3] = state[3][2]; 485 | state[3][2] = state[3][1]; 486 | state[3][1] = temp; 487 | 488 | return; 489 | } 490 | 491 | 492 | /* MixColumn transformation*/ 493 | void MixColumn(u8 state[4][4]) 494 | { 495 | u8 temp, tmp, tmp0; 496 | int i; 497 | 498 | /* do one column at a time */ 499 | for (i=0; i<4;i++) 500 | { 501 | temp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i]; 502 | tmp0 = state[0][i]; 503 | 504 | /* Xtime array does multiply by x in GF2^8 */ 505 | tmp = Xtime[state[0][i] ^ state[1][i]]; 506 | state[0][i] ^= temp ^ tmp; 507 | 508 | tmp = Xtime[state[1][i] ^ state[2][i]]; 509 | state[1][i] ^= temp ^ tmp; 510 | 511 | tmp = Xtime[state[2][i] ^ state[3][i]]; 512 | state[2][i] ^= temp ^ tmp; 513 | 514 | tmp = Xtime[state[3][i] ^ tmp0]; 515 | state[3][i] ^= temp ^ tmp; 516 | } 517 | 518 | return; 519 | } 520 | 521 | 522 | /*------------------------------------------------------------------- 523 | * Rijndael encryption function. Takes 16-byte input and creates 524 | * 16-byte output (using round keys already derived from 16-byte 525 | * key). 526 | *-----------------------------------------------------------------*/ 527 | 528 | void RijndaelEncrypt( u8 input[16], u8 output[16] ) 529 | { 530 | u8 state[4][4]; 531 | int i, r; 532 | 533 | /* initialise state array from input byte string */ 534 | for (i=0; i<16; i++) 535 | state[i & 0x3][i>>2] = input[i]; 536 | 537 | /* add first round_key */ 538 | KeyAdd(state, roundKeys, 0); 539 | 540 | /* do lots of full rounds */ 541 | for (r=1; r<=9; r++) 542 | { 543 | ByteSub(state); 544 | ShiftRow(state); 545 | MixColumn(state); 546 | KeyAdd(state, roundKeys, r); 547 | } 548 | 549 | /* final round */ 550 | ByteSub(state); 551 | ShiftRow(state); 552 | KeyAdd(state, roundKeys, r); 553 | 554 | /* produce output byte string from state array */ 555 | for (i=0; i<16; i++) 556 | { 557 | output[i] = state[i & 0x3][i>>2]; 558 | } 559 | 560 | return; 561 | } /* end of function RijndaelEncrypt */ 562 | 563 | void get_input(u8* output,int length_of_bytes, string name_of_parameter) { 564 | bool got_input_successfully; 565 | string key_input; 566 | do { 567 | got_input_successfully = true; 568 | cout << "please input hex value of " << name_of_parameter << "(no space allowed):"; 569 | cin >> key_input; 570 | while (key_input.length()!=length_of_bytes*2||key_input.find_first_of("ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ")!=string::npos) { 571 | cout << "Error: the length of input string must be " << length_of_bytes*2 << " digits hex value and content must be hex digits!" << endl; 572 | cout << "If the secret key length is less than 32 digits, padded it by all 00" <> key_input; 575 | } 576 | char temp_hex_string[2]; 577 | int num; 578 | char * endptr; 579 | for (int i=0;i> mnc; 602 | while ((mnc.length()!=2 && mnc.length()!=3)||mnc.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")!=string::npos) { 603 | cout << "Error: the length of input string must be 2 or 3 and content must be decimal digits!" << endl; 604 | cout << "please input mnc again:"; 605 | cin >> mnc; 606 | } 607 | cout << "please input mcc (3 decimal digits only):"; 608 | cin >> mcc; 609 | while (mcc.length()!=3||mnc.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")!=string::npos) { 610 | cout << "Error: the length of input string must be 3 and content must be decimal digits!" << endl; 611 | cout << "please input mcc again:"; 612 | cin >> mcc; 613 | } 614 | if (mnc.length()==2){ 615 | mnc="0"+mnc; 616 | } 617 | full_network_name="5G:mnc"+mnc+".mcc"+mcc+".3gppnetwork.org"; 618 | *snn=(u8 *)(full_network_name.c_str()); 619 | // printf("the value of full_network_name is:"); 620 | // for (int i=0;i<32;i++){ 621 | // printf("%02x",*(*snn+sizeof(u8)*i)); 622 | // } 623 | return; 624 | } 625 | 626 | int main( int argc, char *argv[] ) 627 | { 628 | 629 | string menu_selected; 630 | 631 | cout << "######################################################################################"<> menu_selected; 642 | while(menu_selected!="1" && menu_selected!="2"&& menu_selected!="3" && menu_selected!="4" && menu_selected!="5"){ 643 | cout<<"invalid input!please input number <1-5> again:"; 644 | cin >> menu_selected; 645 | } 646 | if (menu_selected=="3"){ 647 | //print out constant value. 648 | print_constant(); 649 | return 0; 650 | }else if (menu_selected=="4"){ 651 | //print out source code of mac and RES calculation. 652 | print_code_mac_res(); 653 | return 0; 654 | }else if (menu_selected=="5"){ 655 | //print out source code of RES* calculation. 656 | print_code_res_star(); 657 | return 0; 658 | }else { 659 | get_input(k,16,"secret key(padded by 00 if less than 16 bytes)"); 660 | 661 | if (menu_selected=="2"){ 662 | use_opc = true; 663 | get_input(op_c,16,"opc"); 664 | } 665 | else if (menu_selected=="1"){ 666 | use_opc = false; 667 | get_input(OP,16,"op"); 668 | } 669 | get_input(rand_value,16,"rand"); 670 | 671 | get_input(autn,16,"AUTN"); 672 | //copy the first 6 bytes of AUTN to sqn_xor_ak. 673 | cout << "\nThe SQN_XOR_AK from network should be first 6 bytes of AUTN, which is (0x): "; 674 | for (int i=0;i<6;i++){ 675 | sqn_xor_ak[i]=autn[i]; 676 | printf("%02x",sqn_xor_ak[i]); 677 | } 678 | cout << "\nThe AMF from network should be the 7th and 8th byte of AUTN, which is (0x): " ; 679 | for (int i=0;i<2;i++){ 680 | amf[i]=autn[i+6]; 681 | printf("%02x",amf[i]); 682 | } 683 | cout << "\nThe MAC-A from network should be the last 8 bytes of AUTN, which is (0x): " ; 684 | for (int i=0;i<8;i++){ 685 | retrieved_mac_a[i]=autn[i+8]; 686 | printf("%02x",retrieved_mac_a[i]); 687 | } 688 | 689 | 690 | } 691 | 692 | f2345( k, rand_value,res,ck,ik,ak); 693 | for (int i=0;i<6;i++){ 694 | sqn[i]=sqn_xor_ak[i]^ak[i]; 695 | } 696 | f1( k, rand_value, sqn,amf,mac_a); 697 | 698 | printf("\nBased on the above provided parameters:\n"); 699 | if (!use_opc){ 700 | cout << "The OPc is computed by encryption of OP value using secret key,then XOR with OP."<> compute_res_star; 746 | while (compute_res_star!="yes" && compute_res_star!="YES" && compute_res_star!="no" && compute_res_star!="NO"){ 747 | cout << "input error: must be yes or no, please try again:"; 748 | cin >> compute_res_star; 749 | } 750 | if (compute_res_star=="yes" || compute_res_star=="YES"){ 751 | u8 *snn; 752 | get_input_snn(&snn); 753 | u8 data_input_sha[63]; 754 | data_input_sha[0]=0x6B; 755 | //copy snn to input 756 | for (int i=0;i<32;i++){ 757 | data_input_sha[1+i]=snn[i]; 758 | } 759 | //length of SNN 760 | data_input_sha[33]=0x00; 761 | data_input_sha[34]=0x20; 762 | //copy rand to input. 763 | for (int i=0;i<16;i++){ 764 | data_input_sha[35+i]=rand_value[i]; 765 | } 766 | //length of rand 767 | data_input_sha[51]=0x00; 768 | data_input_sha[52]=0x10; 769 | //copy RES into input. 770 | for (int i=0;i<8;i++){ 771 | data_input_sha[53+i]=res[i]; 772 | } 773 | //length of RES 774 | data_input_sha[61]=0x00; 775 | data_input_sha[62]=0x08; 776 | //printf("the value of data_input_sha is:"); 777 | //for (int i=0;i<63;i++){ 778 | // printf("%02x",data_input_sha[i]); 779 | //} 780 | u8 key[32]; 781 | for (int i=0;i<16;i++){ 782 | key[i]=ck[i]; 783 | key[16+i]=ik[i]; 784 | } 785 | 786 | //printf("the value of key is:"); 787 | //for (int i=0;i<32;i++){ 788 | // printf("%02x",key[i]); 789 | //} 790 | u8 out[HMAC_SHA256_DIGEST_SIZE]; 791 | hmac_sha256(out,data_input_sha,sizeof(data_input_sha),key,sizeof(key)); 792 | cout << "\nThe RES*(5G) computed based on HMAC_SHA256 in 33.501 should be (0x):"; 793 | for (int i=16;i<32;i++){ 794 | printf("%02x",out[i]); 795 | } 796 | 797 | } 798 | cout << endl << "\ndo you want to continue to compute the SQNms&MAC-S based on the AUTS for sync failure troubleshooting?(yes/no):"; 799 | string compute_sqnms; 800 | cin >> compute_sqnms; 801 | while (compute_sqnms!="yes" && compute_sqnms!="YES" && compute_sqnms!="no" && compute_sqnms!="NO"){ 802 | cout << "input error: must be yes or no, please try again:"; 803 | cin >> compute_sqnms; 804 | } 805 | if (compute_sqnms=="yes" || compute_sqnms=="YES"){ 806 | cout << "Do you want to (1): calculate mac-s by input SQNms&AMF or (2): verify SQNms by input AUTS? Please input 1 or 2:"; 807 | string one_or_two; 808 | cin >> one_or_two; 809 | while (one_or_two!="1" && one_or_two!="2"){ 810 | cout << "input error: must be 1 or 2, please try again:"; 811 | cin >> one_or_two; 812 | } 813 | if (one_or_two=="2"){ 814 | get_input(auts,14,"AUTS"); 815 | cout << "\nThe SQNms_XOR_AK from UE should be first 6 bytes of AUTS, which is (0x): "; 816 | for (int i=0;i<6;i++){ 817 | sqnms_xor_ak[i]=auts[i]; 818 | printf("%02x",sqnms_xor_ak[i]); 819 | } 820 | cout << "\nthe AMF from network is (0x): " ; 821 | for (int i=0;i<2;i++){ 822 | printf("%02x",amf[i]); 823 | } 824 | cout << "\nthe MAC-S retrieved from message should be the last 8 bytes of AUTS, which is (0x): " ; 825 | for (int i=0;i<8;i++){ 826 | retrieved_mac_s[i]=auts[i+6]; 827 | printf("%02x",retrieved_mac_s[i]); 828 | } 829 | f5star(k,rand_value,ak_star); 830 | for (int i=0;i<6;i++){ 831 | sqnms[i]=sqnms_xor_ak[i]^ak_star[i]; 832 | } 833 | cout << "\nthe AK* computed by f5* function in 3gpp 35.206 should be (0x): " ; 834 | 835 | for (int i=0;i<6;i++){ 836 | printf("%02x",ak_star[i]); 837 | } 838 | cout << "\nthe SQNms value should be AK* XOR SQNms_XOR_AK,which is (0x): " ; 839 | for (int i=0;i<6;i++){ 840 | printf("%02x",sqnms[i]); 841 | } 842 | f1star(k,rand_value,sqnms,amf,mac_s); 843 | cout << "\nthe MAC-S computed by f1* function in 3gpp 35.206 should be (0x): " ; 844 | string mac_s_matched= "matched"; 845 | for (int i=0;i<8;i++){ 846 | printf("%02x",mac_s[i]); 847 | if (mac_s[i]!=retrieved_mac_s[i]){ 848 | mac_s_matched= "not matched"; 849 | } 850 | } 851 | cout << "\nthe MAC-S retrieved from message is (0x): " ; 852 | for (int i=0;i<8;i++){ 853 | retrieved_mac_s[i]=auts[i+6]; 854 | printf("%02x",retrieved_mac_s[i]); 855 | } 856 | cout << "\n\nThe computed mac_s and retrieved mac_s from AUTS are " << mac_s_matched << endl; 857 | }else if (one_or_two=="1"){ 858 | get_input(sqnms,6,"SQNms"); 859 | get_input(amf,2,"AMF"); 860 | f1star(k,rand_value,sqnms,amf,mac_s); 861 | cout << "\nthe MAC-S computed by f1* function in 3gpp 35.206 should be (0x): " ; 862 | for (int i=0;i<8;i++){ 863 | printf("%02x",mac_s[i]); 864 | } 865 | f5star(k,rand_value,ak_star); 866 | cout << "\nthe AK* value should be (0x): " ; 867 | for (int i=0;i<6;i++){ 868 | printf("%02x",ak_star[i]); 869 | } 870 | for (int i=0;i<6;i++){ 871 | sqnms_xor_ak[i]=sqnms[i]^ak_star[i]; 872 | } 873 | cout << "\nthe SQNms_XOR_AK(fist 6 bytes of AUTS) value should be (0x): " ; 874 | for (int i=0;i<6;i++){ 875 | printf("%02x",sqnms_xor_ak[i]); 876 | } 877 | cout << endl; 878 | } 879 | 880 | }else{ 881 | return 0; 882 | } 883 | return 0; 884 | } 885 | 886 | 887 | 888 | 889 | 890 | void print_code_mac_res(){ 891 | string code = R"( below source code is from Annex 3 in 3gpp 35.206: 892 | Simulation Program Listing - Byte Oriented 893 | /*------------------------------------------------------------------- 894 | * Example algorithms f1, f1*, f2, f3, f4, f5, f5* 895 | *------------------------------------------------------------------- 896 | * 897 | * A sample implementation of the example 3GPP authentication and 898 | * key agreement functions f1, f1*, f2, f3, f4, f5 and f5*. This is 899 | * a byte-oriented implementation of the functions, and of the block 900 | * cipher kernel function Rijndael. 901 | * 902 | * This has been coded for clarity, not necessarily for efficiency. 903 | * 904 | * The functions f2, f3, f4 and f5 share the same inputs and have 905 | * been coded together as a single function. f1, f1* and f5* are 906 | * all coded separately. 907 | * 908 | *-----------------------------------------------------------------*/ 909 | 910 | typedef unsigned char u8; 911 | 912 | 913 | /*--------- Operator Variant Algorithm Configuration Field --------*/ 914 | 915 | /*------- Insert your value of OP here -------*/ 916 | u8 OP[16] = {0x63, 0xbf, 0xa5, 0x0e, 0xe6, 0x52, 0x33, 0x65, 917 | 0xff, 0x14, 0xc1, 0xf4, 0x5f, 0x88, 0x73, 0x7d}; 918 | /*------- Insert your value of OP here -------*/ 919 | 920 | 921 | /*--------------------------- prototypes --------------------------*/ 922 | 923 | void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 924 | u8 mac_a[8] ); 925 | void f2345 ( u8 k[16], u8 rand[16], 926 | u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ); 927 | void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 928 | u8 mac_s[8] ); 929 | void f5star( u8 k[16], u8 rand[16], 930 | u8 ak[6] ); 931 | void ComputeOPc( u8 op_c[16] ); 932 | void RijndaelKeySchedule( u8 key[16] ); 933 | void RijndaelEncrypt( u8 input[16], u8 output[16] ); 934 | 935 | 936 | /*------------------------------------------------------------------- 937 | * Algorithm f1 938 | *------------------------------------------------------------------- 939 | * 940 | * Computes network authentication code MAC-A from key K, random 941 | * challenge RAND, sequence number SQN and authentication management 942 | * field AMF. 943 | * 944 | *-----------------------------------------------------------------*/ 945 | 946 | void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 947 | u8 mac_a[8] ) 948 | { 949 | u8 op_c[16]; 950 | u8 temp[16]; 951 | u8 in1[16]; 952 | u8 out1[16]; 953 | u8 rijndaelInput[16]; 954 | u8 i; 955 | 956 | RijndaelKeySchedule( k ); 957 | 958 | ComputeOPc( op_c ); 959 | 960 | for (i=0; i<16; i++) 961 | rijndaelInput[i] = rand[i] ^ op_c[i]; 962 | RijndaelEncrypt( rijndaelInput, temp ); 963 | 964 | for (i=0; i<6; i++) 965 | { 966 | in1[i] = sqn[i]; 967 | in1[i+8] = sqn[i]; 968 | } 969 | for (i=0; i<2; i++) 970 | { 971 | in1[i+6] = amf[i]; 972 | in1[i+14] = amf[i]; 973 | } 974 | 975 | /* XOR op_c and in1, rotate by r1=64, and XOR * 976 | * on the constant c1 (which is all zeroes) */ 977 | 978 | for (i=0; i<16; i++) 979 | rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; 980 | 981 | /* XOR on the value temp computed before */ 982 | 983 | for (i=0; i<16; i++) 984 | rijndaelInput[i] ^= temp[i]; 985 | 986 | RijndaelEncrypt( rijndaelInput, out1 ); 987 | for (i=0; i<16; i++) 988 | out1[i] ^= op_c[i]; 989 | 990 | for (i=0; i<8; i++) 991 | mac_a[i] = out1[i]; 992 | 993 | return; 994 | } /* end of function f1 */ 995 | 996 | 997 | 998 | /*------------------------------------------------------------------- 999 | * Algorithms f2-f5 1000 | *------------------------------------------------------------------- 1001 | * 1002 | * Takes key K and random challenge RAND, and returns response RES, 1003 | * confidentiality key CK, integrity key IK and anonymity key AK. 1004 | * 1005 | *-----------------------------------------------------------------*/ 1006 | 1007 | void f2345 ( u8 k[16], u8 rand[16], 1008 | u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ) 1009 | { 1010 | u8 op_c[16]; 1011 | u8 temp[16]; 1012 | u8 out[16]; 1013 | u8 rijndaelInput[16]; 1014 | u8 i; 1015 | 1016 | RijndaelKeySchedule( k ); 1017 | 1018 | ComputeOPc( op_c ); 1019 | 1020 | for (i=0; i<16; i++) 1021 | rijndaelInput[i] = rand[i] ^ op_c[i]; 1022 | RijndaelEncrypt( rijndaelInput, temp ); 1023 | 1024 | /* To obtain output block OUT2: XOR OPc and TEMP, * 1025 | * rotate by r2=0, and XOR on the constant c2 (which * 1026 | * is all zeroes except that the last bit is 1). */ 1027 | 1028 | for (i=0; i<16; i++) 1029 | rijndaelInput[i] = temp[i] ^ op_c[i]; 1030 | rijndaelInput[15] ^= 1; 1031 | 1032 | RijndaelEncrypt( rijndaelInput, out ); 1033 | for (i=0; i<16; i++) 1034 | out[i] ^= op_c[i]; 1035 | 1036 | for (i=0; i<8; i++) 1037 | res[i] = out[i+8]; 1038 | for (i=0; i<6; i++) 1039 | ak[i] = out[i]; 1040 | 1041 | /* To obtain output block OUT3: XOR OPc and TEMP, * 1042 | * rotate by r3=32, and XOR on the constant c3 (which * 1043 | * is all zeroes except that the next to last bit is 1). */ 1044 | 1045 | for (i=0; i<16; i++) 1046 | rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i]; 1047 | rijndaelInput[15] ^= 2; 1048 | 1049 | RijndaelEncrypt( rijndaelInput, out ); 1050 | for (i=0; i<16; i++) 1051 | out[i] ^= op_c[i]; 1052 | 1053 | for (i=0; i<16; i++) 1054 | ck[i] = out[i]; 1055 | 1056 | /* To obtain output block OUT4: XOR OPc and TEMP, * 1057 | * rotate by r4=64, and XOR on the constant c4 (which * 1058 | * is all zeroes except that the 2nd from last bit is 1). */ 1059 | 1060 | for (i=0; i<16; i++) 1061 | rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i]; 1062 | rijndaelInput[15] ^= 4; 1063 | 1064 | RijndaelEncrypt( rijndaelInput, out ); 1065 | for (i=0; i<16; i++) 1066 | out[i] ^= op_c[i]; 1067 | 1068 | for (i=0; i<16; i++) 1069 | ik[i] = out[i]; 1070 | 1071 | return; 1072 | } /* end of function f2345 */ 1073 | 1074 | 1075 | /*------------------------------------------------------------------- 1076 | * Algorithm f1* 1077 | *------------------------------------------------------------------- 1078 | * 1079 | * Computes resynch authentication code MAC-S from key K, random 1080 | * challenge RAND, sequence number SQN and authentication management 1081 | * field AMF. 1082 | * 1083 | *-----------------------------------------------------------------*/ 1084 | 1085 | void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 1086 | u8 mac_s[8] ) 1087 | { 1088 | u8 op_c[16]; 1089 | u8 temp[16]; 1090 | u8 in1[16]; 1091 | u8 out1[16]; 1092 | u8 rijndaelInput[16]; 1093 | u8 i; 1094 | 1095 | RijndaelKeySchedule( k ); 1096 | 1097 | ComputeOPc( op_c ); 1098 | 1099 | for (i=0; i<16; i++) 1100 | rijndaelInput[i] = rand[i] ^ op_c[i]; 1101 | RijndaelEncrypt( rijndaelInput, temp ); 1102 | 1103 | for (i=0; i<6; i++) 1104 | { 1105 | in1[i] = sqn[i]; 1106 | in1[i+8] = sqn[i]; 1107 | } 1108 | for (i=0; i<2; i++) 1109 | { 1110 | in1[i+6] = amf[i]; 1111 | in1[i+14] = amf[i]; 1112 | } 1113 | 1114 | /* XOR op_c and in1, rotate by r1=64, and XOR * 1115 | * on the constant c1 (which is all zeroes) */ 1116 | 1117 | for (i=0; i<16; i++) 1118 | rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; 1119 | 1120 | /* XOR on the value temp computed before */ 1121 | 1122 | for (i=0; i<16; i++) 1123 | rijndaelInput[i] ^= temp[i]; 1124 | 1125 | RijndaelEncrypt( rijndaelInput, out1 ); 1126 | for (i=0; i<16; i++) 1127 | out1[i] ^= op_c[i]; 1128 | 1129 | for (i=0; i<8; i++) 1130 | mac_s[i] = out1[i+8]; 1131 | 1132 | return; 1133 | } /* end of function f1star */ 1134 | 1135 | 1136 | /*------------------------------------------------------------------- 1137 | * Algorithm f5* 1138 | *------------------------------------------------------------------- 1139 | * 1140 | * Takes key K and random challenge RAND, and returns resynch 1141 | * anonymity key AK. 1142 | * 1143 | *-----------------------------------------------------------------*/ 1144 | 1145 | void f5star( u8 k[16], u8 rand[16], 1146 | u8 ak[6] ) 1147 | { 1148 | u8 op_c[16]; 1149 | u8 temp[16]; 1150 | u8 out[16]; 1151 | u8 rijndaelInput[16]; 1152 | u8 i; 1153 | 1154 | RijndaelKeySchedule( k ); 1155 | 1156 | ComputeOPc( op_c ); 1157 | 1158 | for (i=0; i<16; i++) 1159 | rijndaelInput[i] = rand[i] ^ op_c[i]; 1160 | RijndaelEncrypt( rijndaelInput, temp ); 1161 | 1162 | /* To obtain output block OUT5: XOR OPc and TEMP, * 1163 | * rotate by r5=96, and XOR on the constant c5 (which * 1164 | * is all zeroes except that the 3rd from last bit is 1). */ 1165 | 1166 | for (i=0; i<16; i++) 1167 | rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i]; 1168 | rijndaelInput[15] ^= 8; 1169 | 1170 | RijndaelEncrypt( rijndaelInput, out ); 1171 | for (i=0; i<16; i++) 1172 | out[i] ^= op_c[i]; 1173 | 1174 | for (i=0; i<6; i++) 1175 | ak[i] = out[i]; 1176 | 1177 | return; 1178 | } /* end of function f5star */ 1179 | 1180 | 1181 | /*------------------------------------------------------------------- 1182 | * Function to compute OPc from OP and K. Assumes key schedule has 1183 | already been performed. 1184 | *-----------------------------------------------------------------*/ 1185 | 1186 | void ComputeOPc( u8 op_c[16] ) 1187 | { 1188 | u8 i; 1189 | 1190 | RijndaelEncrypt( OP, op_c ); 1191 | for (i=0; i<16; i++) 1192 | op_c[i] ^= OP[i]; 1193 | 1194 | return; 1195 | } /* end of function ComputeOPc */ 1196 | 1197 | 1198 | 1199 | /*-------------------- Rijndael round subkeys ---------------------*/ 1200 | u8 roundKeys[11][4][4]; 1201 | 1202 | /*--------------------- Rijndael S box table ----------------------*/ 1203 | u8 S[256] = { 1204 | 99,124,119,123,242,107,111,197, 48, 1,103, 43,254,215,171,118, 1205 | 202,130,201,125,250, 89, 71,240,173,212,162,175,156,164,114,192, 1206 | 183,253,147, 38, 54, 63,247,204, 52,165,229,241,113,216, 49, 21, 1207 | 4,199, 35,195, 24,150, 5,154, 7, 18,128,226,235, 39,178,117, 1208 | 9,131, 44, 26, 27,110, 90,160, 82, 59,214,179, 41,227, 47,132, 1209 | 83,209, 0,237, 32,252,177, 91,106,203,190, 57, 74, 76, 88,207, 1210 | 208,239,170,251, 67, 77, 51,133, 69,249, 2,127, 80, 60,159,168, 1211 | 81,163, 64,143,146,157, 56,245,188,182,218, 33, 16,255,243,210, 1212 | 205, 12, 19,236, 95,151, 68, 23,196,167,126, 61,100, 93, 25,115, 1213 | 96,129, 79,220, 34, 42,144,136, 70,238,184, 20,222, 94, 11,219, 1214 | 224, 50, 58, 10, 73, 6, 36, 92,194,211,172, 98,145,149,228,121, 1215 | 231,200, 55,109,141,213, 78,169,108, 86,244,234,101,122,174, 8, 1216 | 186,120, 37, 46, 28,166,180,198,232,221,116, 31, 75,189,139,138, 1217 | 112, 62,181,102, 72, 3,246, 14, 97, 53, 87,185,134,193, 29,158, 1218 | 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 1219 | 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22, 1220 | }; 1221 | 1222 | /*------- This array does the multiplication by x in GF(2^8) ------*/ 1223 | u8 Xtime[256] = { 1224 | 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 1225 | 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 1226 | 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 1227 | 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126, 1228 | 128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, 1229 | 160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190, 1230 | 192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222, 1231 | 224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254, 1232 | 27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5, 1233 | 59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37, 1234 | 91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69, 1235 | 123,121,127,125,115,113,119,117,107,105,111,109, 99, 97,103,101, 1236 | 155,153,159,157,147,145,151,149,139,137,143,141,131,129,135,133, 1237 | 187,185,191,189,179,177,183,181,171,169,175,173,163,161,167,165, 1238 | 219,217,223,221,211,209,215,213,203,201,207,205,195,193,199,197, 1239 | 251,249,255,253,243,241,247,245,235,233,239,237,227,225,231,229 1240 | }; 1241 | 1242 | 1243 | /*------------------------------------------------------------------- 1244 | * Rijndael key schedule function. Takes 16-byte key and creates 1245 | * all Rijndael's internal subkeys ready for encryption. 1246 | *-----------------------------------------------------------------*/ 1247 | 1248 | void RijndaelKeySchedule( u8 key[16] ) 1249 | { 1250 | u8 roundConst; 1251 | int i, j; 1252 | 1253 | /* first round key equals key */ 1254 | for (i=0; i<16; i++) 1255 | roundKeys[0][i & 0x03][i>>2] = key[i]; 1256 | 1257 | roundConst = 1; 1258 | 1259 | /* now calculate round keys */ 1260 | for (i=1; i<11; i++) 1261 | { 1262 | roundKeys[i][0][0] = S[roundKeys[i-1][1][3]] 1263 | ^ roundKeys[i-1][0][0] ^ roundConst; 1264 | roundKeys[i][1][0] = S[roundKeys[i-1][2][3]] 1265 | ^ roundKeys[i-1][1][0]; 1266 | roundKeys[i][2][0] = S[roundKeys[i-1][3][3]] 1267 | ^ roundKeys[i-1][2][0]; 1268 | roundKeys[i][3][0] = S[roundKeys[i-1][0][3]] 1269 | ^ roundKeys[i-1][3][0]; 1270 | 1271 | for (j=0; j<4; j++) 1272 | { 1273 | roundKeys[i][j][1] = roundKeys[i-1][j][1] ^ roundKeys[i][j][0]; 1274 | roundKeys[i][j][2] = roundKeys[i-1][j][2] ^ roundKeys[i][j][1]; 1275 | roundKeys[i][j][3] = roundKeys[i-1][j][3] ^ roundKeys[i][j][2]; 1276 | } 1277 | 1278 | /* update round constant */ 1279 | roundConst = Xtime[roundConst]; 1280 | } 1281 | 1282 | return; 1283 | } /* end of function RijndaelKeySchedule */ 1284 | 1285 | 1286 | /* Round key addition function */ 1287 | void KeyAdd(u8 state[4][4], u8 roundKeys[11][4][4], int round) 1288 | { 1289 | int i, j; 1290 | 1291 | for (i=0; i<4; i++) 1292 | for (j=0; j<4; j++) 1293 | state[i][j] ^= roundKeys[round][i][j]; 1294 | 1295 | return; 1296 | } 1297 | 1298 | 1299 | /* Byte substitution transformation */ 1300 | int ByteSub(u8 state[4][4]) 1301 | { 1302 | int i, j; 1303 | 1304 | for (i=0; i<4; i++) 1305 | for (j=0; j<4; j++) 1306 | state[i][j] = S[state[i][j]]; 1307 | 1308 | return 0; 1309 | } 1310 | 1311 | 1312 | /* Row shift transformation */ 1313 | void ShiftRow(u8 state[4][4]) 1314 | { 1315 | u8 temp; 1316 | 1317 | /* left rotate row 1 by 1 */ 1318 | temp = state[1][0]; 1319 | state[1][0] = state[1][1]; 1320 | state[1][1] = state[1][2]; 1321 | state[1][2] = state[1][3]; 1322 | state[1][3] = temp; 1323 | 1324 | /* left rotate row 2 by 2 */ 1325 | temp = state[2][0]; 1326 | state[2][0] = state[2][2]; 1327 | state[2][2] = temp; 1328 | temp = state[2][1]; 1329 | state[2][1] = state[2][3]; 1330 | state[2][3] = temp; 1331 | 1332 | /* left rotate row 3 by 3 */ 1333 | temp = state[3][0]; 1334 | state[3][0] = state[3][3]; 1335 | state[3][3] = state[3][2]; 1336 | state[3][2] = state[3][1]; 1337 | state[3][1] = temp; 1338 | 1339 | return; 1340 | } 1341 | 1342 | 1343 | /* MixColumn transformation*/ 1344 | void MixColumn(u8 state[4][4]) 1345 | { 1346 | u8 temp, tmp, tmp0; 1347 | int i; 1348 | 1349 | /* do one column at a time */ 1350 | for (i=0; i<4;i++) 1351 | { 1352 | temp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i]; 1353 | tmp0 = state[0][i]; 1354 | 1355 | /* Xtime array does multiply by x in GF2^8 */ 1356 | tmp = Xtime[state[0][i] ^ state[1][i]]; 1357 | state[0][i] ^= temp ^ tmp; 1358 | 1359 | tmp = Xtime[state[1][i] ^ state[2][i]]; 1360 | state[1][i] ^= temp ^ tmp; 1361 | 1362 | tmp = Xtime[state[2][i] ^ state[3][i]]; 1363 | state[2][i] ^= temp ^ tmp; 1364 | 1365 | tmp = Xtime[state[3][i] ^ tmp0]; 1366 | state[3][i] ^= temp ^ tmp; 1367 | } 1368 | 1369 | return; 1370 | } 1371 | 1372 | 1373 | /*------------------------------------------------------------------- 1374 | * Rijndael encryption function. Takes 16-byte input and creates 1375 | * 16-byte output (using round keys already derived from 16-byte 1376 | * key). 1377 | *-----------------------------------------------------------------*/ 1378 | 1379 | void RijndaelEncrypt( u8 input[16], u8 output[16] ) 1380 | { 1381 | u8 state[4][4]; 1382 | int i, r; 1383 | 1384 | /* initialise state array from input byte string */ 1385 | for (i=0; i<16; i++) 1386 | state[i & 0x3][i>>2] = input[i]; 1387 | 1388 | /* add first round_key */ 1389 | KeyAdd(state, roundKeys, 0); 1390 | 1391 | /* do lots of full rounds */ 1392 | for (r=1; r<=9; r++) 1393 | { 1394 | ByteSub(state); 1395 | ShiftRow(state); 1396 | MixColumn(state); 1397 | KeyAdd(state, roundKeys, r); 1398 | } 1399 | 1400 | /* final round */ 1401 | ByteSub(state); 1402 | ShiftRow(state); 1403 | KeyAdd(state, roundKeys, r); 1404 | 1405 | /* produce output byte string from state array */ 1406 | for (i=0; i<16; i++) 1407 | { 1408 | output[i] = state[i & 0x3][i>>2]; 1409 | } 1410 | 1411 | return; 1412 | } /* end of function RijndaelEncrypt */ )"; 1413 | cout << code << endl; 1414 | return; 1415 | } 1416 | 1417 | void print_code_res_star(){ 1418 | string code=R"( 1419 | /* below hmac_sha256 source code is from https://github.com/aperezdc/hmac-sha256 */ 1420 | 1421 | void 1422 | sha256_init(sha256_t *p) 1423 | { 1424 | p->state[0] = 0x6a09e667; 1425 | p->state[1] = 0xbb67ae85; 1426 | p->state[2] = 0x3c6ef372; 1427 | p->state[3] = 0xa54ff53a; 1428 | p->state[4] = 0x510e527f; 1429 | p->state[5] = 0x9b05688c; 1430 | p->state[6] = 0x1f83d9ab; 1431 | p->state[7] = 0x5be0cd19; 1432 | p->count = 0; 1433 | } 1434 | 1435 | #define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x, 22)) 1436 | #define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x, 25)) 1437 | #define s0(x) (ROTR32(x, 7) ^ ROTR32(x,18) ^ (x >> 3)) 1438 | #define s1(x) (ROTR32(x,17) ^ ROTR32(x,19) ^ (x >> 10)) 1439 | 1440 | #define blk0(i) (W[i] = data[i]) 1441 | #define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) 1442 | 1443 | #define Ch(x,y,z) (z^(x&(y^z))) 1444 | #define Maj(x,y,z) ((x&y)|(z&(x|y))) 1445 | 1446 | #define a(i) T[(0-(i))&7] 1447 | #define b(i) T[(1-(i))&7] 1448 | #define c(i) T[(2-(i))&7] 1449 | #define d(i) T[(3-(i))&7] 1450 | #define e(i) T[(4-(i))&7] 1451 | #define f(i) T[(5-(i))&7] 1452 | #define g(i) T[(6-(i))&7] 1453 | #define h(i) T[(7-(i))&7] 1454 | 1455 | 1456 | 1457 | #define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ 1458 | d += h; h += S0(a) + Maj(a, b, c) 1459 | 1460 | #define RX_8(i) \ 1461 | R(a,b,c,d,e,f,g,h, i); \ 1462 | R(h,a,b,c,d,e,f,g, (i+1)); \ 1463 | R(g,h,a,b,c,d,e,f, (i+2)); \ 1464 | R(f,g,h,a,b,c,d,e, (i+3)); \ 1465 | R(e,f,g,h,a,b,c,d, (i+4)); \ 1466 | R(d,e,f,g,h,a,b,c, (i+5)); \ 1467 | R(c,d,e,f,g,h,a,b, (i+6)); \ 1468 | R(b,c,d,e,f,g,h,a, (i+7)) 1469 | 1470 | 1471 | static const uint32_t K[64] = { 1472 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 1473 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 1474 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 1475 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 1476 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 1477 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 1478 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 1479 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 1480 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 1481 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 1482 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 1483 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 1484 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 1485 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 1486 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 1487 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 1488 | }; 1489 | 1490 | static void 1491 | sha256_transform(uint32_t *state, const uint32_t *data) 1492 | { 1493 | uint32_t W[16]; 1494 | unsigned j; 1495 | 1496 | uint32_t a,b,c,d,e,f,g,h; 1497 | a = state[0]; 1498 | b = state[1]; 1499 | c = state[2]; 1500 | d = state[3]; 1501 | e = state[4]; 1502 | f = state[5]; 1503 | g = state[6]; 1504 | h = state[7]; 1505 | 1506 | for (j = 0; j < 64; j += 16) 1507 | { 1508 | 1509 | RX_8(0); RX_8(8); 1510 | 1511 | } 1512 | 1513 | 1514 | state[0] += a; 1515 | state[1] += b; 1516 | state[2] += c; 1517 | state[3] += d; 1518 | state[4] += e; 1519 | state[5] += f; 1520 | state[6] += g; 1521 | state[7] += h; 1522 | 1523 | } 1524 | 1525 | #undef S0 1526 | #undef S1 1527 | #undef s0 1528 | #undef s1 1529 | 1530 | static void 1531 | sha256_write_byte_block(sha256_t *p) 1532 | { 1533 | uint32_t data32[16]; 1534 | unsigned i; 1535 | for (i = 0; i < 16; i++) 1536 | data32[i] = 1537 | ((uint32_t)(p->buffer[i * 4 ]) << 24) + 1538 | ((uint32_t)(p->buffer[i * 4 + 1]) << 16) + 1539 | ((uint32_t)(p->buffer[i * 4 + 2]) << 8) + 1540 | ((uint32_t)(p->buffer[i * 4 + 3])); 1541 | sha256_transform(p->state, data32); 1542 | } 1543 | 1544 | 1545 | void 1546 | sha256_hash(unsigned char *buf, const unsigned char *data, size_t size) 1547 | { 1548 | sha256_t hash; 1549 | sha256_init(&hash); 1550 | sha256_update(&hash, data, size); 1551 | sha256_final(&hash, buf); 1552 | } 1553 | 1554 | 1555 | void 1556 | sha256_update(sha256_t *p, const unsigned char *data, size_t size) 1557 | { 1558 | uint32_t curBufferPos = (uint32_t)p->count & 0x3F; 1559 | while (size > 0) 1560 | { 1561 | p->buffer[curBufferPos++] = *data++; 1562 | p->count++; 1563 | size--; 1564 | if (curBufferPos == 64) 1565 | { 1566 | curBufferPos = 0; 1567 | sha256_write_byte_block(p); 1568 | } 1569 | } 1570 | } 1571 | 1572 | 1573 | void 1574 | sha256_final(sha256_t *p, unsigned char *digest) 1575 | { 1576 | uint64_t lenInBits = (p->count << 3); 1577 | uint32_t curBufferPos = (uint32_t)p->count & 0x3F; 1578 | unsigned i; 1579 | p->buffer[curBufferPos++] = 0x80; 1580 | while (curBufferPos != (64 - 8)) 1581 | { 1582 | curBufferPos &= 0x3F; 1583 | if (curBufferPos == 0) 1584 | sha256_write_byte_block(p); 1585 | p->buffer[curBufferPos++] = 0; 1586 | } 1587 | for (i = 0; i < 8; i++) 1588 | { 1589 | p->buffer[curBufferPos++] = (unsigned char)(lenInBits >> 56); 1590 | lenInBits <<= 8; 1591 | } 1592 | sha256_write_byte_block(p); 1593 | 1594 | for (i = 0; i < 8; i++) 1595 | { 1596 | *digest++ = (unsigned char)(p->state[i] >> 24); 1597 | *digest++ = (unsigned char)(p->state[i] >> 16); 1598 | *digest++ = (unsigned char)(p->state[i] >> 8); 1599 | *digest++ = (unsigned char)(p->state[i]); 1600 | } 1601 | sha256_init(p); 1602 | } 1603 | 1604 | 1605 | 1606 | /* 1607 | * HMAC(H, K) == H(K ^ opad, H(K ^ ipad, text)) 1608 | * 1609 | * H: Hash function (sha256) 1610 | * K: Secret key 1611 | * B: Block byte length 1612 | * L: Byte length of hash function output 1613 | * 1614 | * https://tools.ietf.org/html/rfc2104 1615 | */ 1616 | 1617 | #define B 64 1618 | #define L (SHA256_DIGEST_SIZE) 1619 | #define K (SHA256_DIGEST_SIZE * 2) 1620 | 1621 | #define I_PAD 0x36 1622 | #define O_PAD 0x5C 1623 | 1624 | void 1625 | hmac_sha256 (uint8_t out[HMAC_SHA256_DIGEST_SIZE], 1626 | const uint8_t *data, size_t data_len, 1627 | const uint8_t *key, size_t key_len) 1628 | { 1629 | { 1630 | 1631 | sha256_t ss; 1632 | uint8_t kh[SHA256_DIGEST_SIZE]; 1633 | 1634 | /* 1635 | * If the key length is bigger than the buffer size B, apply the hash 1636 | * function to it first and use the result instead. 1637 | */ 1638 | if (key_len > B) { 1639 | sha256_init (&ss); 1640 | sha256_update (&ss, key, key_len); 1641 | sha256_final (&ss, kh); 1642 | key_len = SHA256_DIGEST_SIZE; 1643 | key = kh; 1644 | } 1645 | 1646 | /* 1647 | * (1) append zeros to the end of K to create a B byte string 1648 | * (e.g., if K is of length 20 bytes and B=64, then K will be 1649 | * appended with 44 zero bytes 0x00) 1650 | * (2) XOR (bitwise exclusive-OR) the B byte string computed in step 1651 | * (1) with ipad 1652 | */ 1653 | uint8_t kx[B]; 1654 | for (size_t i = 0; i < key_len; i++) kx[i] = I_PAD ^ key[i]; 1655 | for (size_t i = key_len; i < B; i++) kx[i] = I_PAD ^ 0; 1656 | 1657 | /* 1658 | * (3) append the stream of data 'text' to the B byte string resulting 1659 | * from step (2) 1660 | * (4) apply H to the stream generated in step (3) 1661 | */ 1662 | sha256_init (&ss); 1663 | sha256_update (&ss, kx, B); 1664 | sha256_update (&ss, data, data_len); 1665 | sha256_final (&ss, out); 1666 | 1667 | /* 1668 | * (5) XOR (bitwise exclusive-OR) the B byte string computed in 1669 | * step (1) with opad 1670 | * 1671 | * NOTE: The kx variable is reused. 1672 | */ 1673 | for (size_t i = 0; i < key_len; i++) kx[i] = O_PAD ^ key[i]; 1674 | for (size_t i = key_len; i < B; i++) kx[i] = O_PAD ^ 0; 1675 | 1676 | /* 1677 | * (6) append the H result from step (4) to the B byte string 1678 | * resulting from step (5) 1679 | * (7) apply H to the stream generated in step (6) and output 1680 | * the result 1681 | */ 1682 | sha256_init (&ss); 1683 | sha256_update (&ss, kx, B); 1684 | sha256_update (&ss, out, SHA256_DIGEST_SIZE); 1685 | sha256_final (&ss, out); 1686 | } 1687 | )"; 1688 | cout << code <