├── main ├── libcomp128.a ├── libcomp128_assign.a ├── libcomp128_macos.o ├── Makefile ├── LICENSE ├── comp128.h ├── run.sh ├── Readme.md ├── main.c ├── comp128.py ├── libcomp128.c ├── comp128_orig.c └── libcomp128_base.c /main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LokYan/comp128/HEAD/main -------------------------------------------------------------------------------- /libcomp128.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LokYan/comp128/HEAD/libcomp128.a -------------------------------------------------------------------------------- /libcomp128_assign.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LokYan/comp128/HEAD/libcomp128_assign.a -------------------------------------------------------------------------------- /libcomp128_macos.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LokYan/comp128/HEAD/libcomp128_macos.o -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIB_OBJ=libcomp128.o 2 | MAIN_OBJ=main.o 3 | 4 | CC=gcc 5 | CFLAGS=-I. -L. 6 | 7 | %.o: %.c 8 | $(CC) $(CFLAGS) -c $< -o $@ 9 | 10 | main: $(MAIN_OBJ) 11 | $(CC) $(CFLAGS) $^ -lcomp128 -o $@ 12 | 13 | lib: $(LIB_OBJ) 14 | ar rcs libcomp128.a libcomp128.o 15 | 16 | assignment: $(MAIN_OBJ) 17 | $(CC) $(CFLAGS) $^ -lcomp128_assign -o $@ 18 | 19 | clean: 20 | rm -f *.o 21 | rm -f main 22 | rm -f assignment 23 | 24 | clean-all: 25 | rm -f libcomp128.a 26 | rm -f *.o 27 | rm -f main 28 | rm -f assignment 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Lok Yan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /comp128.h: -------------------------------------------------------------------------------- 1 | #ifndef COMP128_H 2 | #define COMP128_H 3 | 4 | #include 5 | #include 6 | 7 | typedef unsigned char Byte; 8 | 9 | /** 10 | * The main COMP128 function 11 | **/ 12 | 13 | void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16], 14 | /* out */ Byte simoutput[12]); 15 | 16 | /** 17 | * A function with a built in key 18 | **/ 19 | 20 | void A3A8_Challenge(Byte rand[16], Byte simoutput[12]); 21 | 22 | /** 23 | * A helper function to print hex to string. 24 | **/ 25 | static void snprintHex(char* dst, Byte* s, int len) 26 | { 27 | for (int i = 0; i < len; i++) 28 | { 29 | sprintf(dst + (i*2), "%02X", s[i]); 30 | } 31 | } 32 | 33 | /** 34 | * A helper function print hex to FILE 35 | **/ 36 | static void fprintHex(FILE* outf, Byte* s, int len) 37 | { 38 | for (int i = 0; i < len; i++) 39 | { 40 | fprintf(outf, "%02X", s[i]); 41 | } 42 | } 43 | 44 | #define printHex(s, l) fprintHex(stdout, s, l) 45 | 46 | /** 47 | * A helper function to turn a hex char into an int 48 | **/ 49 | static int hextoint(char x) 50 | { 51 | x = toupper(x); 52 | if ( (x >= 'A') && (x <= 'F') ) 53 | { 54 | return ( (x - 'A') + 10 ); 55 | } 56 | else if ( (x >= 'a') && (x <= 'f') ) 57 | { 58 | return ( (x - 'a') + 10 ); 59 | } 60 | else if ( (x >= '0') && (x <= '9') ) 61 | { 62 | return (x - '0'); 63 | } 64 | return (-1); 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HEX=("00" "01" "02" "03" "04" "05" "06" "07" 4 | "08" "09" "0A" "0B" "0C" "0D" "0E" "0F" 5 | "10" "11" "12" "13" "14" "15" "16" "17" 6 | "18" "19" "1A" "1B" "1C" "1D" "1E" "1F" 7 | "20" "21" "22" "23" "24" "25" "26" "27" 8 | "28" "29" "2A" "2B" "2C" "2D" "2E" "2F" 9 | "30" "31" "32" "33" "34" "35" "36" "37" 10 | "38" "39" "3A" "3B" "3C" "3D" "3E" "3F" 11 | "40" "41" "42" "43" "44" "45" "46" "47" 12 | "48" "49" "4A" "4B" "4C" "4D" "4E" "4F" 13 | "50" "51" "52" "53" "54" "55" "56" "57" 14 | "58" "59" "5A" "5B" "5C" "5D" "5E" "5F" 15 | "60" "61" "62" "63" "64" "65" "66" "67" 16 | "68" "69" "6A" "6B" "6C" "6D" "6E" "6F" 17 | "70" "71" "72" "73" "74" "75" "76" "77" 18 | "78" "79" "7A" "7B" "7C" "7D" "7E" "7F" 19 | "80" "81" "82" "83" "84" "85" "86" "87" 20 | "88" "89" "8A" "8B" "8C" "8D" "8E" "8F" 21 | "90" "91" "92" "93" "94" "95" "96" "97" 22 | "98" "99" "9A" "9B" "9C" "9D" "9E" "9F" 23 | "A0" "A1" "A2" "A3" "A4" "A5" "A6" "A7" 24 | "A8" "A9" "AA" "AB" "AC" "AD" "AE" "AF" 25 | "B0" "B1" "B2" "B3" "B4" "B5" "B6" "B7" 26 | "B8" "B9" "BA" "BB" "BC" "BD" "BE" "BF" 27 | "C0" "C1" "C2" "C3" "C4" "C5" "C6" "C7" 28 | "C8" "C9" "CA" "CB" "CC" "CD" "CE" "CF" 29 | "D0" "D1" "D2" "D3" "D4" "D5" "D6" "D7" 30 | "D8" "D9" "DA" "DB" "DC" "DD" "DE" "DF" 31 | "E0" "E1" "E2" "E3" "E4" "E5" "E6" "E7" 32 | "E8" "E9" "EA" "EB" "EC" "ED" "EE" "EF" 33 | "F0" "F1" "F2" "F3" "F4" "F5" "F6" "F7" 34 | "F8" "F9" "FA" "FB" "FC" "FD" "FE" "FF") 35 | 36 | BITPOS=$1 37 | 38 | CMDPREFIX="" 39 | CMDSUFFIX="" 40 | for ((i = 0; i < ${BITPOS}; i++)); do 41 | CMDPREFIX+="00" 42 | done 43 | 44 | for ((i = 0; i < (7 - ${BITPOS}); i++)); do 45 | CMDSUFFIX+="00" 46 | done 47 | 48 | for i in ${HEX[@]} ; do 49 | date 50 | echo $i 51 | for j in ${HEX[@]} ; do 52 | ./main 0x${CMDPREFIX}${i}${CMDSUFFIX}${CMDPREFIX}${j}${CMDSUFFIX} ${BITPOS} && exit 0 53 | done 54 | done 55 | 56 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # COMP128 Exercise 2 | 3 | COMP128 is a well known cryptographic algorithm that implemented the A3 (Authentication) and A8 (Key Agreement) functions of the GSM standard. Like other contemporary algorithms, COMP128 was proprietary and buggy. We studied the "narrow pipe" issue by Wagner, Goldberg, and Briceno (http://www.isaac.cs.berkeley.edu/isaac/gsm-faq.html) in our mobile security course and this is an opportunity to test out the bug. 4 | 5 | The researchers also released a recovered (some internal documentation was leaked to the public) and reverse engineered a version of the A3A8 algorithm written in C. This repository is that source, but in a form that is suitable as an assignment/lab/exercise. 6 | 7 | ## Source Layout 8 | 9 | The original source code is found in comp128\_orig.c and the same source (plus a couple of helper functions) was separated into a shared-library (libcomp128.c) as well as a main function (main.c) that can be used to perform a brute-force search to find collisions. We also created a sample bash script (run.sh) that can be used to run a brute force attempt. Finally, a python version of comp128 is also provided (comp128.py) for students who would rather play with Python (although it is much slower). 10 | 11 | ## Idea Behind the Assignment 12 | 13 | For the assignment, students are provided with a libcomp128.a (see Makefile) that was precompiled with a secret key. Students are then asked to make changes to the source to 1. find collisions at each of the 8 byte position pairs and 2. use the colliding inputs (challenges) to find the corresponding key bytes. 14 | 15 | ## Sample Run of repository 16 | 17 | lok@lok:~/Desktop/comp128$ ls 18 | comp128.h comp128.py libcomp128.c main.c Makefile Readme.md run.sh 19 | lok@lok:~/Desktop/comp128$ 20 | lok@lok:~/Desktop/comp128$ make lib 21 | gcc -I. -L. -c libcomp128.c -o libcomp128.o 22 | ar rcs libcomp128.a libcomp128.o 23 | lok@lok:~/Desktop/comp128$ 24 | lok@lok:~/Desktop/comp128$ make 25 | gcc -I. -L. -c main.c -o main.o 26 | gcc -I. -L. main.o -lcomp128 -o main 27 | lok@lok:~/Desktop/comp128$ 28 | lok@lok:~/Desktop/comp128$ python3 comp128.py 29 | Output from original program 30 | A3A8(1D000000000000009900000000000000,048BC1EA93B0F82733D67C19267C91D6) = 80B3A76AD121F66903D0F800 31 | 32 | A3A8(3E00000000000000C100000000000000,048BC1EA93B0F82733D67C19267C91D6) = 80B3A76AD121F66903D0F800 33 | 34 | Output from this script 35 | A3A8(1D000000000000009900000000000000,048BC1EA93B0F82733D67C19267C91D6) = 80B3A76AD121F66903D0F800 36 | A3A8(3E00000000000000C100000000000000,048BC1EA93B0F82733D67C19267C91D6) = 80B3A76AD121F66903D0F800 37 | lok@lok:~/Desktop/comp128$ 38 | lok@lok:~/Desktop/comp128$ 39 | lok@lok:~/Desktop/comp128$ ./main 0x3E00000000000000C100000000000000 0 0x1D 40 | 3E00000000000000C100000000000000 41 | 80B3A76AD121F66903D0F800 42 | 1D000000000000009900000000000000 43 | 80B3A76AD121F66903D0F800 44 | 45 | ## Other Modes of Operation 46 | 47 | This COMP128 program has three modes of operation in total: the brute force mode as shown above, the base mode where you can pass in both the random challenge and the key to use, and then there is the rand-only mode where you pass in the random challenge and the built-in key (the one that is being brute-forced is used). The brute force mode is useful for finding collisions, the base mode is good for finding the key and the rand-only mode is good for verifying that you have the right key. 48 | 49 | ### Sample Run of other modes 50 | 51 | lok@lok:~/Desktop/comp128$ ./main 0x12341234123412341234123412341234 52 | 9CD2E0434EE92690CE71D800 53 | lok@lok:~/Desktop/comp128$ 54 | lok@lok:~/Desktop/comp128$ ./main 0x12341234123412341234123412341234 0x048bc1ea93b0f82733d67c19267c91d6 55 | 9CD2E0434EE92690CE71D800 56 | lok@lok:~/Desktop/comp128$ 57 | lok@lok:~/Desktop/comp128$ 58 | lok@lok:~/Desktop/comp128$ ./main 0x00001234123412341234123412340000 59 | 136A205ED174EE8175944400 60 | lok@lok:~/Desktop/comp128$ 61 | lok@lok:~/Desktop/comp128$ ./main 0x00001234123412341234123412340000 0x048bc1ea93b0f82733d67c19267c91d6 62 | 136A205ED174EE8175944400 63 | 64 | # LICENSE 65 | 66 | Copyright 2021 Lok Yan 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 69 | 70 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 71 | 72 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 73 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "comp128.h" 2 | 3 | #include 4 | 5 | //Included to address warnings 6 | #include 7 | #include 8 | #include 9 | 10 | void printUsage(FILE* outf, char* argv0) 11 | { 12 | fprintf(outf, "Usage: %s 0x 0x \n", argv0); 13 | fprintf(outf, " Computes COMP128 for and \n"); 14 | fprintf(outf, "\n"); 15 | fprintf(outf, "Usage: %s 0x \n", argv0); 16 | fprintf(outf, " Computes COMP128 for using built in key.\n"); 17 | fprintf(outf, "\n"); 18 | fprintf(outf, "Usage: %s 0x bytePos [0x] [0x]\n", argv0); 19 | fprintf(outf, " Run COMP128 in brute force mode on built in key\n"); 20 | fprintf(outf, " User passes in a challenge and the program \n"); 21 | fprintf(outf, " iterates through all possible 2^16 combinations of values\n"); 22 | fprintf(outf, " at byte positions bytePos and bytePos+8. \n"); 23 | fprintf(outf, " [0x] and [0x] are optional. \n"); 24 | fprintf(outf, " Example: %s 0xCA00000000000000FE00000000000000 0 \n", argv0); 25 | fprintf(outf, " Iterates from 0x00000000000000000000000000000000 to \n"); 26 | fprintf(outf, " 0xFF00000000000000FF00000000000000 \n"); 27 | fprintf(outf, " and compares the output with that of 0xCA...FE...\n"); 28 | fprintf(outf, " %s 0xCA00000000000000FE00000000000000 1 0x12 0x34 \n", argv0); 29 | fprintf(outf, " Iterates from 0x00120000000000000000000000000000 to \n"); 30 | fprintf(outf, " 0x003400000000000000FF000000000000 \n"); 31 | } 32 | 33 | int main(int argc, char **argv) 34 | { 35 | Byte rand[16] = { 0x00, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00}; 39 | Byte rand2[16] = {0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00}; 43 | Byte simoutput[12]; 44 | Byte simoutput2[12]; 45 | int bitPos = 0; 46 | int start = 0; 47 | int end = 0; 48 | int i = 0; 49 | int j = 0; 50 | 51 | if ( (argc < 2) 52 | || (strlen(argv[1]) != 34) 53 | || (strncmp(argv[1], "0x", 2) != 0) 54 | ) 55 | { 56 | printUsage(stderr, argv[0]); 57 | exit(1); 58 | } 59 | 60 | for (i=0; i<16; i++) 61 | { 62 | rand[i] = (hextoint(argv[1][2*i+2])<<4) 63 | | hextoint(argv[1][2*i+3]); 64 | } 65 | 66 | //first case where we are using built-in key 67 | if (argc == 2) 68 | { 69 | A3A8_Challenge(rand, simoutput); 70 | printHex(simoutput, 12); 71 | printf("\n"); 72 | return (0); 73 | } 74 | 75 | //next process the COMP128 base case 76 | if ( strncmp(argv[2], "0x", 2) == 0 ) 77 | { 78 | for (i=0; i<16; i++) 79 | { 80 | rand2[i] = (hextoint(argv[2][2*i+2])<<4) 81 | | hextoint(argv[2][2*i+3]); 82 | } 83 | 84 | A3A8(rand, rand2, simoutput); 85 | printHex(simoutput, 12); 86 | printf("\n"); 87 | return (0); 88 | } 89 | 90 | //if its the other option 91 | bitPos = (argv[2][0] - '0'); 92 | if ( (bitPos < 0) || (bitPos > 7) ) 93 | { 94 | printUsage(stderr, argv[0]); 95 | exit(1); 96 | } 97 | 98 | if (argc >= 4) 99 | { 100 | if (strncmp(argv[3], "0x", 2) != 0) 101 | { 102 | printUsage(stderr, argv[0]); 103 | exit(1); 104 | } 105 | 106 | start = (hextoint(argv[3][2])<<4) 107 | | hextoint(argv[3][3]); 108 | } 109 | else 110 | { 111 | start = 0x00; 112 | } 113 | 114 | if (argc == 5) 115 | { 116 | if (strncmp(argv[4], "0x", 2) != 0) 117 | { 118 | printUsage(stderr, argv[0]); 119 | exit(1); 120 | } 121 | 122 | end = (hextoint(argv[4][2])<<4) 123 | | hextoint(argv[4][3]); 124 | } 125 | else 126 | { 127 | end = 0xFF; 128 | } 129 | 130 | A3A8_Challenge(rand, simoutput); 131 | 132 | for (i = start; i <= end ; i++) 133 | { 134 | for (j = 0; j < 0x100; j++) 135 | { 136 | rand2[bitPos] = i; 137 | rand2[bitPos+8] = j; 138 | if (rand[bitPos] == rand2[bitPos] && rand[bitPos+8] == rand2[bitPos+8]) 139 | { 140 | continue; 141 | } 142 | A3A8_Challenge(rand2, simoutput2); 143 | if (memcmp(simoutput, simoutput2, 12) == 0) 144 | { 145 | printHex(rand, 16); 146 | printf("\n"); 147 | printHex(simoutput, 12); 148 | printf("\n"); 149 | printHex(rand2, 16); 150 | printf("\n"); 151 | printHex(simoutput2, 12); 152 | printf("\n"); 153 | return 0; 154 | } 155 | } 156 | } 157 | return 1; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /comp128.py: -------------------------------------------------------------------------------- 1 | #COMP128 Algorithm Converted from C to Python. 2 | # Original is from Marc Briceno, Ian Goldberg, and David Wagner. 3 | # Original C can be found at the end of this file, 4 | # including the error where key and rand are swapped 5 | # in the main function. 6 | 7 | s_table = [ 8 | [ 102,177,186,162, 2,156,112, 75, 55, 25, 8, 12,251,193,246,188, 9 | 109,213,151, 53, 42, 79,191,115,233,242,164,223,209,148,108,161, 10 | 252, 37,244, 47, 64,211, 6,237,185,160,139,113, 76,138, 59, 70, 11 | 67, 26, 13,157, 63,179,221, 30,214, 36,166, 69,152,124,207,116, 12 | 247,194, 41, 84, 71, 1, 49, 14, 95, 35,169, 21, 96, 78,215,225, 13 | 182,243, 28, 92,201,118, 4, 74,248,128, 17, 11,146,132,245, 48, 14 | 149, 90,120, 39, 87,230,106,232,175, 19,126,190,202,141,137,176, 15 | 250, 27,101, 40,219,227, 58, 20, 51,178, 98,216,140, 22, 32,121, 16 | 61,103,203, 72, 29,110, 85,212,180,204,150,183, 15, 66,172,196, 17 | 56,197,158, 0,100, 45,153, 7,144,222,163,167, 60,135,210,231, 18 | 174,165, 38,249,224, 34,220,229,217,208,241, 68,206,189,125,255, 19 | 239, 54,168, 89,123,122, 73,145,117,234,143, 99,129,200,192, 82, 20 | 104,170,136,235, 93, 81,205,173,236, 94,105, 52, 46,228,198, 5, 21 | 57,254, 97,155,142,133,199,171,187, 50, 65,181,127,107,147,226, 22 | 184,218,131, 33, 77, 86, 31, 44, 88, 62,238, 18, 24, 43,154, 23, 23 | 80,159,134,111, 9,114, 3, 91, 16,130, 83, 10,195,240,253,119, 24 | 177,102,162,186,156, 2, 75,112, 25, 55, 12, 8,193,251,188,246, 25 | 213,109, 53,151, 79, 42,115,191,242,233,223,164,148,209,161,108, 26 | 37,252, 47,244,211, 64,237, 6,160,185,113,139,138, 76, 70, 59, 27 | 26, 67,157, 13,179, 63, 30,221, 36,214, 69,166,124,152,116,207, 28 | 194,247, 84, 41, 1, 71, 14, 49, 35, 95, 21,169, 78, 96,225,215, 29 | 243,182, 92, 28,118,201, 74, 4,128,248, 11, 17,132,146, 48,245, 30 | 90,149, 39,120,230, 87,232,106, 19,175,190,126,141,202,176,137, 31 | 27,250, 40,101,227,219, 20, 58,178, 51,216, 98, 22,140,121, 32, 32 | 103, 61, 72,203,110, 29,212, 85,204,180,183,150, 66, 15,196,172, 33 | 197, 56, 0,158, 45,100, 7,153,222,144,167,163,135, 60,231,210, 34 | 165,174,249, 38, 34,224,229,220,208,217, 68,241,189,206,255,125, 35 | 54,239, 89,168,122,123,145, 73,234,117, 99,143,200,129, 82,192, 36 | 170,104,235,136, 81, 93,173,205, 94,236, 52,105,228, 46, 5,198, 37 | 254, 57,155, 97,133,142,171,199, 50,187,181, 65,107,127,226,147, 38 | 218,184, 33,131, 86, 77, 44, 31, 62, 88, 18,238, 43, 24, 23,154, 39 | 159, 80,111,134,114, 9, 91, 3,130, 16, 10, 83,240,195,119,253 40 | ] , 41 | [ 42 | 19, 11, 80,114, 43, 1, 69, 94, 39, 18,127,117, 97, 3, 85, 43, 43 | 27,124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, 44 | 35,107,103, 68, 21, 86, 36, 91, 85,126, 32, 50,109, 94,120, 6, 45 | 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55,110,125,105, 20, 46 | 90, 80, 76, 96, 23, 60, 89, 64,121, 56, 14, 74,101, 8, 19, 78, 47 | 76, 66,104, 46,111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, 48 | 57, 65,119,116, 22,109, 7, 86, 59, 93, 62,110, 78, 99, 77, 67, 49 | 12,113, 87, 98,102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, 50 | 95, 63, 28, 49,123,120, 20,112, 44, 30, 15, 98,106, 2,103, 29, 51 | 82,107, 42,124, 24, 30, 41, 16,108,100,117, 40, 73, 40, 7,114, 52 | 82,115, 36,112, 12,102,100, 84, 92, 48, 72, 97, 9, 54, 55, 74, 53 | 113,123, 17, 26, 53, 58, 4, 9, 69,122, 21,118, 42, 60, 27, 73, 54 | 118,125, 34, 15, 65,115, 84, 64, 62, 81, 70, 1, 24,111,121, 83, 55 | 104, 81, 49,127, 48,105, 31, 10, 6, 91, 87, 37, 16, 54,116,126, 56 | 31, 38, 13, 0, 72,106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, 57 | 101, 17, 44,108, 71, 52, 66, 57, 33, 51, 25, 90, 2,119,122, 35 58 | ], 59 | [ 60 | 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, 61 | 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, 62 | 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, 63 | 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, 64 | 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, 65 | 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, 66 | 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, 67 | 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7 68 | ], 69 | [ 70 | 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, 71 | 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, 72 | 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, 73 | 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19 74 | ], 75 | [ 76 | 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, 77 | 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12 78 | ] 79 | ] 80 | 81 | def comp128(rand, key) : 82 | #Byte x[32], bit[128]; 83 | x = [0]*32 84 | bit = [0]*128 85 | simoutput = [0]*12 86 | 87 | #/* ( Load RAND into last 16 bytes of input ) */ 88 | for i in range(16,32) : 89 | x[i] = rand[i-16]; 90 | 91 | #/* ( Loop eight times ) */ 92 | for i in range (1,9) : 93 | #/* ( Load key into first 16 bytes of input ) */ 94 | for j in range(0,16) : 95 | x[j] = key[j] 96 | #/* ( Perform substitutions ) */ 97 | for j in range(0,5) : 98 | for k in range(0,1<>(3-k)) & 1 110 | #/* ( Permutation but not on the last loop ) */ 111 | if (i < 8) : 112 | for j in range(0,16) : 113 | x[j+16] = 0 114 | for k in range(0,8) : 115 | next_bit = ((8*j + k)*17) % 128 116 | x[j+16] |= bit[next_bit] << (7-k) 117 | 118 | #/* 119 | # * ( At this stage the vector x[] consists of 32 nibbles. 120 | # * The first 8 of these are taken as the output SRES. ) 121 | # */ 122 | 123 | #/* The remainder of the code is not given explicitly in the 124 | # * standard, but was derived by reverse-engineering. 125 | # */ 126 | 127 | for i in range(0,4) : 128 | simoutput[i] = (x[2*i]<<4) | x[2*i+1] 129 | for i in range(0,6) : 130 | simoutput[4+i] = (x[2*i+18]<<6) | (x[2*i+18+1]<<2) | (x[2*i+18+2]>>2) 131 | simoutput[4+6] = (x[2*6+18]<<6) | (x[2*6+18+1]<<2) 132 | simoutput[4+7] = 0 133 | 134 | #simoutput can be larger than a byte so truncate 135 | simoutput = [0xFF & _ for _ in simoutput] 136 | return simoutput 137 | 138 | 139 | #Test 140 | 141 | key = "0x048BC1EA93B0F82733D67C19267C91D6" 142 | rand1 = "0x1D000000000000009900000000000000" 143 | rand2 = "0x3E00000000000000C100000000000000" 144 | 145 | #Compare with Original C version 146 | import subprocess 147 | 148 | def callOriginal(r, k) : 149 | sout = "" 150 | proc = subprocess.Popen(["./main", r, k], stdout=subprocess.PIPE) 151 | try: 152 | sout, serr = proc.communicate(timeout=5) #5 seconds should be good? 153 | except TimeoutExpired: 154 | proc.kill() #kill the process 155 | sout, serr = proc.communicate() 156 | print("Process Killed") 157 | print("stdout") 158 | print(sout) 159 | print("stderr") 160 | print(serr) 161 | return sout 162 | 163 | oout1 = callOriginal(rand1, key) 164 | oout2 = callOriginal(rand2, key) 165 | 166 | 167 | key_ia = [int(_) for _ in bytearray.fromhex(key[2:])] 168 | rand1_ia = [int(_) for _ in bytearray.fromhex(rand1[2:])] 169 | rand2_ia = [int(_) for _ in bytearray.fromhex(rand2[2:])] 170 | out1 = comp128(rand1_ia, key_ia) 171 | out2 = comp128(rand2_ia, key_ia) 172 | 173 | key_hex = [format(_, "02X") for _ in key_ia] 174 | rand1_hex = [format(_, "02X") for _ in rand1_ia] 175 | rand2_hex = [format(_, "02X") for _ in rand2_ia] 176 | out1_hex = [format(_, "02X") for _ in out1] 177 | out2_hex = [format(_, "02X") for _ in out2] 178 | key_str = "".join(key_hex) 179 | rand1_str = "".join(rand1_hex) 180 | rand2_str = "".join(rand2_hex) 181 | out1_str = "".join(out1_hex) 182 | out2_str = "".join(out2_hex) 183 | 184 | print ("Output from original program") 185 | print ("A3A8(%s,%s) = %s" % (rand1_str, key_str, (oout1.decode("ascii")))) #Print it out as ascii 186 | print ("A3A8(%s,%s) = %s" % (rand2_str, key_str, (oout2.decode("ascii")))) #Print it out as ascii 187 | 188 | print ("Output from this script") 189 | print ("A3A8(%s,%s) = %s" % (rand1_str, key_str, out1_str)) 190 | print ("A3A8(%s,%s) = %s" % (rand2_str, key_str, out1_str)) 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /libcomp128.c: -------------------------------------------------------------------------------- 1 | /* An implementation of the GSM A3A8 algorithm. (Specifically, COMP128.) 2 | */ 3 | 4 | /* Copyright 1998, Marc Briceno, Ian Goldberg, and David Wagner. 5 | * All rights reserved. 6 | */ 7 | 8 | /* 9 | * For expository purposes only. Coded in C merely because C is a much 10 | * more precise, concise form of expression for these purposes. See Judge 11 | * Patel if you have any problems with this... 12 | * Of course, it's only authentication, so it should be exportable for the 13 | * usual boring reasons. 14 | */ 15 | 16 | /** 17 | * Changed into a library for exercise purposes 18 | **/ 19 | 20 | #include "comp128.h" 21 | 22 | /* 23 | * rand[0..15]: the challenge from the base station 24 | * key[0..15]: the SIM's A3/A8 long-term key Ki 25 | * simoutput[0..11]: what you'd get back if you fed rand and key to a real 26 | * SIM. 27 | * 28 | * The GSM spec states that simoutput[0..3] is SRES, 29 | * and simoutput[4..11] is Kc (the A5 session key). 30 | * (See GSM 11.11, Section 8.16. See also the leaked document 31 | * referenced below.) 32 | * Note that Kc is bits 74..127 of the COMP128 output, followed by 10 33 | * zeros. 34 | * In other words, A5 is keyed with only 54 bits of entropy. This 35 | * represents a deliberate weakening of the key used for voice privacy 36 | * by a factor of over 1000. 37 | * 38 | * Verified with a Pacific Bell Schlumberger SIM. Your mileage may vary. 39 | * 40 | * Marc Briceno , Ian Goldberg , 41 | * and David Wagner 42 | */ 43 | 44 | /* The compression tables. */ 45 | static const Byte table_0[512] = { 46 | 102,177,186,162, 2,156,112, 75, 55, 25, 8, 12,251,193,246,188, 47 | 109,213,151, 53, 42, 79,191,115,233,242,164,223,209,148,108,161, 48 | 252, 37,244, 47, 64,211, 6,237,185,160,139,113, 76,138, 59, 70, 49 | 67, 26, 13,157, 63,179,221, 30,214, 36,166, 69,152,124,207,116, 50 | 247,194, 41, 84, 71, 1, 49, 14, 95, 35,169, 21, 96, 78,215,225, 51 | 182,243, 28, 92,201,118, 4, 74,248,128, 17, 11,146,132,245, 48, 52 | 149, 90,120, 39, 87,230,106,232,175, 19,126,190,202,141,137,176, 53 | 250, 27,101, 40,219,227, 58, 20, 51,178, 98,216,140, 22, 32,121, 54 | 61,103,203, 72, 29,110, 85,212,180,204,150,183, 15, 66,172,196, 55 | 56,197,158, 0,100, 45,153, 7,144,222,163,167, 60,135,210,231, 56 | 174,165, 38,249,224, 34,220,229,217,208,241, 68,206,189,125,255, 57 | 239, 54,168, 89,123,122, 73,145,117,234,143, 99,129,200,192, 82, 58 | 104,170,136,235, 93, 81,205,173,236, 94,105, 52, 46,228,198, 5, 59 | 57,254, 97,155,142,133,199,171,187, 50, 65,181,127,107,147,226, 60 | 184,218,131, 33, 77, 86, 31, 44, 88, 62,238, 18, 24, 43,154, 23, 61 | 80,159,134,111, 9,114, 3, 91, 16,130, 83, 10,195,240,253,119, 62 | 177,102,162,186,156, 2, 75,112, 25, 55, 12, 8,193,251,188,246, 63 | 213,109, 53,151, 79, 42,115,191,242,233,223,164,148,209,161,108, 64 | 37,252, 47,244,211, 64,237, 6,160,185,113,139,138, 76, 70, 59, 65 | 26, 67,157, 13,179, 63, 30,221, 36,214, 69,166,124,152,116,207, 66 | 194,247, 84, 41, 1, 71, 14, 49, 35, 95, 21,169, 78, 96,225,215, 67 | 243,182, 92, 28,118,201, 74, 4,128,248, 11, 17,132,146, 48,245, 68 | 90,149, 39,120,230, 87,232,106, 19,175,190,126,141,202,176,137, 69 | 27,250, 40,101,227,219, 20, 58,178, 51,216, 98, 22,140,121, 32, 70 | 103, 61, 72,203,110, 29,212, 85,204,180,183,150, 66, 15,196,172, 71 | 197, 56, 0,158, 45,100, 7,153,222,144,167,163,135, 60,231,210, 72 | 165,174,249, 38, 34,224,229,220,208,217, 68,241,189,206,255,125, 73 | 54,239, 89,168,122,123,145, 73,234,117, 99,143,200,129, 82,192, 74 | 170,104,235,136, 81, 93,173,205, 94,236, 52,105,228, 46, 5,198, 75 | 254, 57,155, 97,133,142,171,199, 50,187,181, 65,107,127,226,147, 76 | 218,184, 33,131, 86, 77, 44, 31, 62, 88, 18,238, 43, 24, 23,154, 77 | 159, 80,111,134,114, 9, 91, 3,130, 16, 10, 83,240,195,119,253 78 | }, table_1[256] = { 79 | 19, 11, 80,114, 43, 1, 69, 94, 39, 18,127,117, 97, 3, 85, 43, 80 | 27,124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, 81 | 35,107,103, 68, 21, 86, 36, 91, 85,126, 32, 50,109, 94,120, 6, 82 | 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55,110,125,105, 20, 83 | 90, 80, 76, 96, 23, 60, 89, 64,121, 56, 14, 74,101, 8, 19, 78, 84 | 76, 66,104, 46,111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, 85 | 57, 65,119,116, 22,109, 7, 86, 59, 93, 62,110, 78, 99, 77, 67, 86 | 12,113, 87, 98,102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, 87 | 95, 63, 28, 49,123,120, 20,112, 44, 30, 15, 98,106, 2,103, 29, 88 | 82,107, 42,124, 24, 30, 41, 16,108,100,117, 40, 73, 40, 7,114, 89 | 82,115, 36,112, 12,102,100, 84, 92, 48, 72, 97, 9, 54, 55, 74, 90 | 113,123, 17, 26, 53, 58, 4, 9, 69,122, 21,118, 42, 60, 27, 73, 91 | 118,125, 34, 15, 65,115, 84, 64, 62, 81, 70, 1, 24,111,121, 83, 92 | 104, 81, 49,127, 48,105, 31, 10, 6, 91, 87, 37, 16, 54,116,126, 93 | 31, 38, 13, 0, 72,106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, 94 | 101, 17, 44,108, 71, 52, 66, 57, 33, 51, 25, 90, 2,119,122, 35 95 | }, table_2[128] = { 96 | 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, 97 | 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, 98 | 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, 99 | 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, 100 | 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, 101 | 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, 102 | 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, 103 | 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7 104 | }, table_3[64] = { 105 | 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, 106 | 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, 107 | 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, 108 | 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19 109 | }, table_4[32] = { 110 | 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, 111 | 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12 112 | }, *table[5] = { table_0, table_1, table_2, table_3, table_4 }; 113 | 114 | /* 115 | * This code derived from a leaked document from the GSM standards. 116 | * Some missing pieces were filled in by reverse-engineering a working SIM. 117 | * We have verified that this is the correct COMP128 algorithm. 118 | * 119 | * The first page of the document identifies it as 120 | * _Technical Information: GSM System Security Study_. 121 | * 10-1617-01, 10th June 1988. 122 | * The bottom of the title page is marked 123 | * Racal Research Ltd. 124 | * Worton Drive, Worton Grange Industrial Estate, 125 | * Reading, Berks. RG2 0SB, England. 126 | * Telephone: Reading (0734) 868601 Telex: 847152 127 | * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! 128 | * 129 | * Note: There are three typos in the spec (discovered by 130 | * reverse-engineering). 131 | * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read 132 | * "z = (2 * x[m] + x[n]) mod 2^(9-j)". 133 | * Second, the "k" loop in the "Form bits from bytes" section is severely 134 | * botched: the k index should run only from 0 to 3, and clearly the range 135 | * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, 136 | * to be consistent with the subsequent section). 137 | * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as 138 | * claimed in the document. (And the document doesn't specify how Kc is 139 | * derived, but that was also easily discovered with reverse engineering.) 140 | * All of these typos have been corrected in the following code. 141 | */ 142 | 143 | void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16], 144 | /* out */ Byte simoutput[12]) 145 | { 146 | Byte x[32], bit[128]; 147 | int i, j, k, l, m, n, y, z, next_bit; 148 | 149 | /* ( Load RAND into last 16 bytes of input ) */ 150 | for (i=16; i<32; i++) { 151 | x[i] = rand[i-16]; 152 | } 153 | 154 | /* ( Loop eight times ) */ 155 | for (i=1; i<9; i++) { 156 | /* ( Load key into first 16 bytes of input ) */ 157 | for (j=0; j<16; j++) { 158 | x[j] = key[j]; 159 | } 160 | /* ( Perform substitutions ) */ 161 | for (j=0; j<5; j++) { 162 | for (k=0; k<(1<>(3-k)) & 1; 178 | } 179 | } 180 | /* ( Permutation but not on the last loop ) */ 181 | if (i < 8) { 182 | for (j=0; j<16; j++) { 183 | x[j+16] = 0; 184 | for (k=0; k<8; k++) { 185 | next_bit = ((8*j + k)*17) % 128; 186 | x[j+16] |= bit[next_bit] << (7-k); 187 | } 188 | } 189 | } 190 | } 191 | 192 | /* 193 | * ( At this stage the vector x[] consists of 32 nibbles. 194 | * The first 8 of these are taken as the output SRES. ) 195 | */ 196 | 197 | /* The remainder of the code is not given explicitly in the 198 | * standard, but was derived by reverse-engineering. 199 | */ 200 | 201 | for (i=0; i<4; i++) { 202 | simoutput[i] = (x[2*i]<<4) | x[2*i+1]; 203 | } 204 | for (i=0; i<6; i++) { 205 | simoutput[4+i] = (x[2*i+18]<<6) | (x[2*i+18+1]<<2) 206 | | (x[2*i+18+2]>>2); 207 | } 208 | simoutput[4+6] = (x[2*6+18]<<6) | (x[2*6+18+1]<<2); 209 | simoutput[4+7] = 0; 210 | } 211 | 212 | void A3A8_Challenge(Byte rand[16], Byte simoutput[12]) 213 | { 214 | Byte key2[16] = {0x04, 0x8B, 0xC1, 0xEA, 215 | 0x93, 0xB0, 0xF8, 0x27, 216 | 0x33, 0xD6, 0x7C, 0x19, 217 | 0x26, 0x7C, 0x91, 0xD6}; 218 | 219 | A3A8(rand, key2, simoutput); 220 | } 221 | 222 | -------------------------------------------------------------------------------- /comp128_orig.c: -------------------------------------------------------------------------------- 1 | /** 2 | * A cleaned up version of the original code can be found below. Cleanup includes: 3 | * 1. Including more libraries to suppress undefined warnings 4 | * 2. Added braces to for loops for clarity 5 | * 3. Fixed bug in main function where calling A3A8 had key and rand swapped 6 | */ 7 | 8 | /* An implementation of the GSM A3A8 algorithm. (Specifically, COMP128.) 9 | */ 10 | 11 | /* Copyright 1998, Marc Briceno, Ian Goldberg, and David Wagner. 12 | * All rights reserved. 13 | */ 14 | 15 | /* 16 | * For expository purposes only. Coded in C merely because C is a much1 17 | * more precise, concise form of expression for these purposes. See Judge 18 | * Patel if you have any problems with this... 19 | * Of course, it's only authentication, so it should be exportable for the 20 | * usual boring reasons. 21 | */ 22 | 23 | typedef unsigned char Byte; 24 | 25 | #include 26 | 27 | //Included to address warnings 28 | #include 29 | #include 30 | #include 31 | 32 | //define TEST for testing 33 | #define TEST 34 | 35 | /* 36 | * rand[0..15]: the challenge from the base station 37 | * key[0..15]: the SIM's A3/A8 long-term key Ki 38 | * simoutput[0..11]: what you'd get back if you fed rand and key to a real 39 | * SIM. 40 | * 41 | * The GSM spec states that simoutput[0..3] is SRES, 42 | * and simoutput[4..11] is Kc (the A5 session key). 43 | * (See GSM 11.11, Section 8.16. See also the leaked document 44 | * referenced below.) 45 | * Note that Kc is bits 74..127 of the COMP128 output, followed by 10 46 | * zeros. 47 | * In other words, A5 is keyed with only 54 bits of entropy. This 48 | * represents a deliberate weakening of the key used for voice privacy 49 | * by a factor of over 1000. 50 | * 51 | * Verified with a Pacific Bell Schlumberger SIM. Your mileage may vary. 52 | * 53 | * Marc Briceno , Ian Goldberg , 54 | * and David Wagner 55 | */ 56 | 57 | void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16], 58 | /* out */ Byte simoutput[12]); 59 | 60 | /* The compression tables. */ 61 | static const Byte table_0[512] = { 62 | 102,177,186,162, 2,156,112, 75, 55, 25, 8, 12,251,193,246,188, 63 | 109,213,151, 53, 42, 79,191,115,233,242,164,223,209,148,108,161, 64 | 252, 37,244, 47, 64,211, 6,237,185,160,139,113, 76,138, 59, 70, 65 | 67, 26, 13,157, 63,179,221, 30,214, 36,166, 69,152,124,207,116, 66 | 247,194, 41, 84, 71, 1, 49, 14, 95, 35,169, 21, 96, 78,215,225, 67 | 182,243, 28, 92,201,118, 4, 74,248,128, 17, 11,146,132,245, 48, 68 | 149, 90,120, 39, 87,230,106,232,175, 19,126,190,202,141,137,176, 69 | 250, 27,101, 40,219,227, 58, 20, 51,178, 98,216,140, 22, 32,121, 70 | 61,103,203, 72, 29,110, 85,212,180,204,150,183, 15, 66,172,196, 71 | 56,197,158, 0,100, 45,153, 7,144,222,163,167, 60,135,210,231, 72 | 174,165, 38,249,224, 34,220,229,217,208,241, 68,206,189,125,255, 73 | 239, 54,168, 89,123,122, 73,145,117,234,143, 99,129,200,192, 82, 74 | 104,170,136,235, 93, 81,205,173,236, 94,105, 52, 46,228,198, 5, 75 | 57,254, 97,155,142,133,199,171,187, 50, 65,181,127,107,147,226, 76 | 184,218,131, 33, 77, 86, 31, 44, 88, 62,238, 18, 24, 43,154, 23, 77 | 80,159,134,111, 9,114, 3, 91, 16,130, 83, 10,195,240,253,119, 78 | 177,102,162,186,156, 2, 75,112, 25, 55, 12, 8,193,251,188,246, 79 | 213,109, 53,151, 79, 42,115,191,242,233,223,164,148,209,161,108, 80 | 37,252, 47,244,211, 64,237, 6,160,185,113,139,138, 76, 70, 59, 81 | 26, 67,157, 13,179, 63, 30,221, 36,214, 69,166,124,152,116,207, 82 | 194,247, 84, 41, 1, 71, 14, 49, 35, 95, 21,169, 78, 96,225,215, 83 | 243,182, 92, 28,118,201, 74, 4,128,248, 11, 17,132,146, 48,245, 84 | 90,149, 39,120,230, 87,232,106, 19,175,190,126,141,202,176,137, 85 | 27,250, 40,101,227,219, 20, 58,178, 51,216, 98, 22,140,121, 32, 86 | 103, 61, 72,203,110, 29,212, 85,204,180,183,150, 66, 15,196,172, 87 | 197, 56, 0,158, 45,100, 7,153,222,144,167,163,135, 60,231,210, 88 | 165,174,249, 38, 34,224,229,220,208,217, 68,241,189,206,255,125, 89 | 54,239, 89,168,122,123,145, 73,234,117, 99,143,200,129, 82,192, 90 | 170,104,235,136, 81, 93,173,205, 94,236, 52,105,228, 46, 5,198, 91 | 254, 57,155, 97,133,142,171,199, 50,187,181, 65,107,127,226,147, 92 | 218,184, 33,131, 86, 77, 44, 31, 62, 88, 18,238, 43, 24, 23,154, 93 | 159, 80,111,134,114, 9, 91, 3,130, 16, 10, 83,240,195,119,253 94 | }, table_1[256] = { 95 | 19, 11, 80,114, 43, 1, 69, 94, 39, 18,127,117, 97, 3, 85, 43, 96 | 27,124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, 97 | 35,107,103, 68, 21, 86, 36, 91, 85,126, 32, 50,109, 94,120, 6, 98 | 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55,110,125,105, 20, 99 | 90, 80, 76, 96, 23, 60, 89, 64,121, 56, 14, 74,101, 8, 19, 78, 100 | 76, 66,104, 46,111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, 101 | 57, 65,119,116, 22,109, 7, 86, 59, 93, 62,110, 78, 99, 77, 67, 102 | 12,113, 87, 98,102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, 103 | 95, 63, 28, 49,123,120, 20,112, 44, 30, 15, 98,106, 2,103, 29, 104 | 82,107, 42,124, 24, 30, 41, 16,108,100,117, 40, 73, 40, 7,114, 105 | 82,115, 36,112, 12,102,100, 84, 92, 48, 72, 97, 9, 54, 55, 74, 106 | 113,123, 17, 26, 53, 58, 4, 9, 69,122, 21,118, 42, 60, 27, 73, 107 | 118,125, 34, 15, 65,115, 84, 64, 62, 81, 70, 1, 24,111,121, 83, 108 | 104, 81, 49,127, 48,105, 31, 10, 6, 91, 87, 37, 16, 54,116,126, 109 | 31, 38, 13, 0, 72,106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, 110 | 101, 17, 44,108, 71, 52, 66, 57, 33, 51, 25, 90, 2,119,122, 35 111 | }, table_2[128] = { 112 | 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, 113 | 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, 114 | 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, 115 | 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, 116 | 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, 117 | 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, 118 | 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, 119 | 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7 120 | }, table_3[64] = { 121 | 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, 122 | 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, 123 | 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, 124 | 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19 125 | }, table_4[32] = { 126 | 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, 127 | 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12 128 | }, *table[5] = { table_0, table_1, table_2, table_3, table_4 }; 129 | 130 | /* 131 | * This code derived from a leaked document from the GSM standards. 132 | * Some missing pieces were filled in by reverse-engineering a working SIM. 133 | * We have verified that this is the correct COMP128 algorithm. 134 | * 135 | * The first page of the document identifies it as 136 | * _Technical Information: GSM System Security Study_. 137 | * 10-1617-01, 10th June 1988. 138 | * The bottom of the title page is marked 139 | * Racal Research Ltd. 140 | * Worton Drive, Worton Grange Industrial Estate, 141 | * Reading, Berks. RG2 0SB, England. 142 | * Telephone: Reading (0734) 868601 Telex: 847152 143 | * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! 144 | * 145 | * Note: There are three typos in the spec (discovered by 146 | * reverse-engineering). 147 | * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read 148 | * "z = (2 * x[m] + x[n]) mod 2^(9-j)". 149 | * Second, the "k" loop in the "Form bits from bytes" section is severely 150 | * botched: the k index should run only from 0 to 3, and clearly the range 151 | * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, 152 | * to be consistent with the subsequent section). 153 | * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as 154 | * claimed in the document. (And the document doesn't specify how Kc is 155 | * derived, but that was also easily discovered with reverse engineering.) 156 | * All of these typos have been corrected in the following code. 157 | */ 158 | 159 | void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16], 160 | /* out */ Byte simoutput[12]) 161 | { 162 | Byte x[32], bit[128]; 163 | int i, j, k, l, m, n, y, z, next_bit; 164 | 165 | /* ( Load RAND into last 16 bytes of input ) */ 166 | for (i=16; i<32; i++) { 167 | x[i] = rand[i-16]; 168 | } 169 | 170 | /* ( Loop eight times ) */ 171 | for (i=1; i<9; i++) { 172 | /* ( Load key into first 16 bytes of input ) */ 173 | for (j=0; j<16; j++) { 174 | x[j] = key[j]; 175 | } 176 | /* ( Perform substitutions ) */ 177 | for (j=0; j<5; j++) { 178 | for (k=0; k<(1<>(3-k)) & 1; 193 | } 194 | } 195 | /* ( Permutation but not on the last loop ) */ 196 | if (i < 8) { 197 | for (j=0; j<16; j++) { 198 | x[j+16] = 0; 199 | for (k=0; k<8; k++) { 200 | next_bit = ((8*j + k)*17) % 128; 201 | x[j+16] |= bit[next_bit] << (7-k); 202 | } 203 | } 204 | } 205 | } 206 | 207 | /* 208 | * ( At this stage the vector x[] consists of 32 nibbles. 209 | * The first 8 of these are taken as the output SRES. ) 210 | */ 211 | 212 | /* The remainder of the code is not given explicitly in the 213 | * standard, but was derived by reverse-engineering. 214 | */ 215 | 216 | for (i=0; i<4; i++) { 217 | simoutput[i] = (x[2*i]<<4) | x[2*i+1]; 218 | } 219 | for (i=0; i<6; i++) { 220 | simoutput[4+i] = (x[2*i+18]<<6) | (x[2*i+18+1]<<2) 221 | | (x[2*i+18+2]>>2); 222 | } 223 | simoutput[4+6] = (x[2*6+18]<<6) | (x[2*6+18+1]<<2); 224 | simoutput[4+7] = 0; 225 | } 226 | 227 | 228 | #ifdef TEST 229 | int hextoint(char x) 230 | { 231 | x = toupper(x); 232 | if (x >= 'A' && x <= 'F') { 233 | return x-'A'+10; 234 | } 235 | else if (x >= '0' && x <= '9') { 236 | return x-'0'; 237 | } 238 | fprintf(stderr, "bad input.\n"); 239 | exit(1); 240 | } 241 | 242 | int main(int argc, char **argv) 243 | { 244 | Byte key[16], rand[16], simoutput[12]; 245 | int i; 246 | 247 | if (argc != 3 || strlen(argv[1]) != 34 || strlen(argv[2]) != 34 248 | || strncmp(argv[1], "0x", 2) != 0 249 | || strncmp(argv[2], "0x", 2) != 0) { 250 | fprintf(stderr, "Usage: %s 0x 0x\n", argv[0]); 251 | exit(1); 252 | } 253 | 254 | for (i=0; i<16; i++) { 255 | key[i] = (hextoint(argv[1][2*i+2])<<4) 256 | | hextoint(argv[1][2*i+3]); 257 | } 258 | for (i=0; i<16; i++) { 259 | rand[i] = (hextoint(argv[2][2*i+2])<<4) 260 | | hextoint(argv[2][2*i+3]); 261 | } 262 | 263 | //Original Call swaps key and rand. Fixed. 264 | //A3A8(key, rand, simoutput); 265 | A3A8(rand, key, simoutput); 266 | printf("simoutput: "); 267 | for (i=0; i<12; i++) { 268 | printf("%02X", simoutput[i]); 269 | } 270 | printf("\n"); 271 | return 0; 272 | } 273 | #endif 274 | 275 | -------------------------------------------------------------------------------- /libcomp128_base.c: -------------------------------------------------------------------------------- 1 | /* An implementation of the GSM A3A8 algorithm. (Specifically, COMP128.) 2 | */ 3 | 4 | /* Copyright 1998, Marc Briceno, Ian Goldberg, and David Wagner. 5 | * All rights reserved. 6 | */ 7 | 8 | /* 9 | * For expository purposes only. Coded in C merely because C is a much 10 | * more precise, concise form of expression for these purposes. See Judge 11 | * Patel if you have any problems with this... 12 | * Of course, it's only authentication, so it should be exportable for the 13 | * usual boring reasons. 14 | */ 15 | 16 | /** 17 | * Changed into a library for exercise purposes 18 | **/ 19 | 20 | #include "comp128.h" 21 | 22 | /* 23 | * rand[0..15]: the challenge from the base station 24 | * key[0..15]: the SIM's A3/A8 long-term key Ki 25 | * simoutput[0..11]: what you'd get back if you fed rand and key to a real 26 | * SIM. 27 | * 28 | * The GSM spec states that simoutput[0..3] is SRES, 29 | * and simoutput[4..11] is Kc (the A5 session key). 30 | * (See GSM 11.11, Section 8.16. See also the leaked document 31 | * referenced below.) 32 | * Note that Kc is bits 74..127 of the COMP128 output, followed by 10 33 | * zeros. 34 | * In other words, A5 is keyed with only 54 bits of entropy. This 35 | * represents a deliberate weakening of the key used for voice privacy 36 | * by a factor of over 1000. 37 | * 38 | * Verified with a Pacific Bell Schlumberger SIM. Your mileage may vary. 39 | * 40 | * Marc Briceno , Ian Goldberg , 41 | * and David Wagner 42 | */ 43 | 44 | /* The compression tables. */ 45 | static const Byte table_0[512] = { 46 | 102,177,186,162, 2,156,112, 75, 55, 25, 8, 12,251,193,246,188, 47 | 109,213,151, 53, 42, 79,191,115,233,242,164,223,209,148,108,161, 48 | 252, 37,244, 47, 64,211, 6,237,185,160,139,113, 76,138, 59, 70, 49 | 67, 26, 13,157, 63,179,221, 30,214, 36,166, 69,152,124,207,116, 50 | 247,194, 41, 84, 71, 1, 49, 14, 95, 35,169, 21, 96, 78,215,225, 51 | 182,243, 28, 92,201,118, 4, 74,248,128, 17, 11,146,132,245, 48, 52 | 149, 90,120, 39, 87,230,106,232,175, 19,126,190,202,141,137,176, 53 | 250, 27,101, 40,219,227, 58, 20, 51,178, 98,216,140, 22, 32,121, 54 | 61,103,203, 72, 29,110, 85,212,180,204,150,183, 15, 66,172,196, 55 | 56,197,158, 0,100, 45,153, 7,144,222,163,167, 60,135,210,231, 56 | 174,165, 38,249,224, 34,220,229,217,208,241, 68,206,189,125,255, 57 | 239, 54,168, 89,123,122, 73,145,117,234,143, 99,129,200,192, 82, 58 | 104,170,136,235, 93, 81,205,173,236, 94,105, 52, 46,228,198, 5, 59 | 57,254, 97,155,142,133,199,171,187, 50, 65,181,127,107,147,226, 60 | 184,218,131, 33, 77, 86, 31, 44, 88, 62,238, 18, 24, 43,154, 23, 61 | 80,159,134,111, 9,114, 3, 91, 16,130, 83, 10,195,240,253,119, 62 | 177,102,162,186,156, 2, 75,112, 25, 55, 12, 8,193,251,188,246, 63 | 213,109, 53,151, 79, 42,115,191,242,233,223,164,148,209,161,108, 64 | 37,252, 47,244,211, 64,237, 6,160,185,113,139,138, 76, 70, 59, 65 | 26, 67,157, 13,179, 63, 30,221, 36,214, 69,166,124,152,116,207, 66 | 194,247, 84, 41, 1, 71, 14, 49, 35, 95, 21,169, 78, 96,225,215, 67 | 243,182, 92, 28,118,201, 74, 4,128,248, 11, 17,132,146, 48,245, 68 | 90,149, 39,120,230, 87,232,106, 19,175,190,126,141,202,176,137, 69 | 27,250, 40,101,227,219, 20, 58,178, 51,216, 98, 22,140,121, 32, 70 | 103, 61, 72,203,110, 29,212, 85,204,180,183,150, 66, 15,196,172, 71 | 197, 56, 0,158, 45,100, 7,153,222,144,167,163,135, 60,231,210, 72 | 165,174,249, 38, 34,224,229,220,208,217, 68,241,189,206,255,125, 73 | 54,239, 89,168,122,123,145, 73,234,117, 99,143,200,129, 82,192, 74 | 170,104,235,136, 81, 93,173,205, 94,236, 52,105,228, 46, 5,198, 75 | 254, 57,155, 97,133,142,171,199, 50,187,181, 65,107,127,226,147, 76 | 218,184, 33,131, 86, 77, 44, 31, 62, 88, 18,238, 43, 24, 23,154, 77 | 159, 80,111,134,114, 9, 91, 3,130, 16, 10, 83,240,195,119,253 78 | }, table_1[256] = { 79 | 19, 11, 80,114, 43, 1, 69, 94, 39, 18,127,117, 97, 3, 85, 43, 80 | 27,124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, 81 | 35,107,103, 68, 21, 86, 36, 91, 85,126, 32, 50,109, 94,120, 6, 82 | 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55,110,125,105, 20, 83 | 90, 80, 76, 96, 23, 60, 89, 64,121, 56, 14, 74,101, 8, 19, 78, 84 | 76, 66,104, 46,111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, 85 | 57, 65,119,116, 22,109, 7, 86, 59, 93, 62,110, 78, 99, 77, 67, 86 | 12,113, 87, 98,102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, 87 | 95, 63, 28, 49,123,120, 20,112, 44, 30, 15, 98,106, 2,103, 29, 88 | 82,107, 42,124, 24, 30, 41, 16,108,100,117, 40, 73, 40, 7,114, 89 | 82,115, 36,112, 12,102,100, 84, 92, 48, 72, 97, 9, 54, 55, 74, 90 | 113,123, 17, 26, 53, 58, 4, 9, 69,122, 21,118, 42, 60, 27, 73, 91 | 118,125, 34, 15, 65,115, 84, 64, 62, 81, 70, 1, 24,111,121, 83, 92 | 104, 81, 49,127, 48,105, 31, 10, 6, 91, 87, 37, 16, 54,116,126, 93 | 31, 38, 13, 0, 72,106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, 94 | 101, 17, 44,108, 71, 52, 66, 57, 33, 51, 25, 90, 2,119,122, 35 95 | }, table_2[128] = { 96 | 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, 97 | 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, 98 | 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, 99 | 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, 100 | 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, 101 | 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, 102 | 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, 103 | 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7 104 | }, table_3[64] = { 105 | 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, 106 | 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, 107 | 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, 108 | 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19 109 | }, table_4[32] = { 110 | 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, 111 | 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12 112 | }, *table[5] = { table_0, table_1, table_2, table_3, table_4 }; 113 | 114 | /* 115 | * This code derived from a leaked document from the GSM standards. 116 | * Some missing pieces were filled in by reverse-engineering a working SIM. 117 | * We have verified that this is the correct COMP128 algorithm. 118 | * 119 | * The first page of the document identifies it as 120 | * _Technical Information: GSM System Security Study_. 121 | * 10-1617-01, 10th June 1988. 122 | * The bottom of the title page is marked 123 | * Racal Research Ltd. 124 | * Worton Drive, Worton Grange Industrial Estate, 125 | * Reading, Berks. RG2 0SB, England. 126 | * Telephone: Reading (0734) 868601 Telex: 847152 127 | * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! 128 | * 129 | * Note: There are three typos in the spec (discovered by 130 | * reverse-engineering). 131 | * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read 132 | * "z = (2 * x[m] + x[n]) mod 2^(9-j)". 133 | * Second, the "k" loop in the "Form bits from bytes" section is severely 134 | * botched: the k index should run only from 0 to 3, and clearly the range 135 | * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, 136 | * to be consistent with the subsequent section). 137 | * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as 138 | * claimed in the document. (And the document doesn't specify how Kc is 139 | * derived, but that was also easily discovered with reverse engineering.) 140 | * All of these typos have been corrected in the following code. 141 | */ 142 | 143 | void A3A8(/* in */ Byte rand[16], /* in */ Byte key[16], 144 | /* out */ Byte simoutput[12]) 145 | { 146 | Byte x[32], bit[128]; 147 | int i, j, k, l, m, n, y, z, next_bit; 148 | 149 | /* ( Load RAND into last 16 bytes of input ) */ 150 | for (i=16; i<32; i++) { 151 | x[i] = rand[i-16]; 152 | } 153 | 154 | /* ( Loop eight times ) */ 155 | for (i=1; i<9; i++) { 156 | /* ( Load key into first 16 bytes of input ) */ 157 | for (j=0; j<16; j++) { 158 | x[j] = key[j]; 159 | } 160 | /* ( Perform substitutions ) */ 161 | for (j=0; j<5; j++) { 162 | for (k=0; k<(1<>(3-k)) & 1; 178 | } 179 | } 180 | /* ( Permutation but not on the last loop ) */ 181 | if (i < 8) { 182 | for (j=0; j<16; j++) { 183 | x[j+16] = 0; 184 | for (k=0; k<8; k++) { 185 | next_bit = ((8*j + k)*17) % 128; 186 | x[j+16] |= bit[next_bit] << (7-k); 187 | } 188 | } 189 | } 190 | } 191 | 192 | /* 193 | * ( At this stage the vector x[] consists of 32 nibbles. 194 | * The first 8 of these are taken as the output SRES. ) 195 | */ 196 | 197 | /* The remainder of the code is not given explicitly in the 198 | * standard, but was derived by reverse-engineering. 199 | */ 200 | 201 | for (i=0; i<4; i++) { 202 | simoutput[i] = (x[2*i]<<4) | x[2*i+1]; 203 | } 204 | for (i=0; i<6; i++) { 205 | simoutput[4+i] = (x[2*i+18]<<6) | (x[2*i+18+1]<<2) 206 | | (x[2*i+18+2]>>2); 207 | } 208 | simoutput[4+6] = (x[2*6+18]<<6) | (x[2*6+18+1]<<2); 209 | simoutput[4+7] = 0; 210 | } 211 | 212 | Byte key[16] = {0xFF, 0xEE, 0xDD, 0xCC, 213 | 0xBB, 0xAA, 0x99, 0x88, 214 | 0x77, 0x66, 0x55, 0x44, 215 | 0x33, 0x22, 0x11, 0x00}; 216 | 217 | void A3A8_Challenge(Byte rand[16], Byte simoutput[12]) 218 | { 219 | char locals[32]; 220 | __asm__("nop"); 221 | __asm__("nop"); 222 | __asm__("nop"); 223 | __asm__("nop"); 224 | __asm__("nop"); 225 | __asm__("nop"); 226 | __asm__("nop"); 227 | __asm__("nop"); 228 | __asm__("nop"); 229 | __asm__("nop"); 230 | __asm__("nop"); 231 | __asm__("nop"); 232 | __asm__("nop"); 233 | __asm__("nop"); 234 | __asm__("nop"); 235 | __asm__("nop"); 236 | __asm__("nop"); 237 | __asm__("nop"); 238 | __asm__("nop"); 239 | __asm__("nop"); 240 | __asm__("nop"); 241 | __asm__("nop"); 242 | __asm__("nop"); 243 | __asm__("nop"); 244 | __asm__("nop"); 245 | __asm__("nop"); 246 | __asm__("nop"); 247 | __asm__("nop"); 248 | __asm__("nop"); 249 | __asm__("nop"); 250 | __asm__("nop"); 251 | __asm__("nop"); 252 | __asm__("nop"); 253 | __asm__("nop"); 254 | __asm__("nop"); 255 | __asm__("nop"); 256 | __asm__("nop"); 257 | __asm__("nop"); 258 | __asm__("nop"); 259 | __asm__("nop"); 260 | __asm__("nop"); 261 | __asm__("nop"); 262 | __asm__("nop"); 263 | __asm__("nop"); 264 | __asm__("nop"); 265 | __asm__("nop"); 266 | __asm__("nop"); 267 | __asm__("nop"); 268 | __asm__("nop"); 269 | __asm__("nop"); 270 | __asm__("nop"); 271 | __asm__("nop"); 272 | __asm__("nop"); 273 | __asm__("nop"); 274 | __asm__("nop"); 275 | __asm__("nop"); 276 | __asm__("nop"); 277 | __asm__("nop"); 278 | __asm__("nop"); 279 | __asm__("nop"); 280 | __asm__("nop"); 281 | __asm__("nop"); 282 | __asm__("nop"); 283 | __asm__("nop"); 284 | __asm__("nop"); 285 | __asm__("nop"); 286 | __asm__("nop"); 287 | __asm__("nop"); 288 | __asm__("nop"); 289 | __asm__("nop"); 290 | __asm__("nop"); 291 | __asm__("nop"); 292 | __asm__("nop"); 293 | __asm__("nop"); 294 | __asm__("nop"); 295 | __asm__("nop"); 296 | __asm__("nop"); 297 | __asm__("nop"); 298 | __asm__("nop"); 299 | __asm__("nop"); 300 | __asm__("nop"); 301 | __asm__("nop"); 302 | __asm__("nop"); 303 | __asm__("nop"); 304 | __asm__("nop"); 305 | __asm__("nop"); 306 | __asm__("nop"); 307 | __asm__("nop"); 308 | __asm__("nop"); 309 | __asm__("nop"); 310 | __asm__("nop"); 311 | __asm__("nop"); 312 | __asm__("nop"); 313 | __asm__("nop"); 314 | __asm__("nop"); 315 | __asm__("nop"); 316 | __asm__("nop"); 317 | __asm__("nop"); 318 | __asm__("nop"); 319 | __asm__("nop"); 320 | __asm__("nop"); 321 | __asm__("nop"); 322 | __asm__("nop"); 323 | __asm__("nop"); 324 | __asm__("nop"); 325 | __asm__("nop"); 326 | __asm__("nop"); 327 | __asm__("nop"); 328 | __asm__("nop"); 329 | __asm__("nop"); 330 | __asm__("nop"); 331 | __asm__("nop"); 332 | __asm__("nop"); 333 | __asm__("nop"); 334 | __asm__("nop"); 335 | __asm__("nop"); 336 | __asm__("nop"); 337 | __asm__("nop"); 338 | __asm__("nop"); 339 | __asm__("nop"); 340 | __asm__("nop"); 341 | __asm__("nop"); 342 | __asm__("nop"); 343 | __asm__("nop"); 344 | __asm__("nop"); 345 | __asm__("nop"); 346 | __asm__("nop"); 347 | __asm__("nop"); 348 | __asm__("nop"); 349 | __asm__("nop"); 350 | __asm__("nop"); 351 | __asm__("nop"); 352 | __asm__("nop"); 353 | __asm__("nop"); 354 | __asm__("nop"); 355 | __asm__("nop"); 356 | __asm__("nop"); 357 | __asm__("nop"); 358 | __asm__("nop"); 359 | __asm__("nop"); 360 | __asm__("nop"); 361 | __asm__("nop"); 362 | __asm__("nop"); 363 | __asm__("nop"); 364 | __asm__("nop"); 365 | __asm__("nop"); 366 | __asm__("nop"); 367 | __asm__("nop"); 368 | __asm__("nop"); 369 | __asm__("nop"); 370 | A3A8(rand, key, simoutput); 371 | 372 | } 373 | 374 | --------------------------------------------------------------------------------