Enigma Decoding Problem - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Enigma Decoding Problem (/thread-41279.html) |
Enigma Decoding Problem - krisarmstrong - Dec-12-2023 I have been working on a Python application. It was initially coded in C++. I have the encoding working however the decoding is not producing the expected results. Encode Functions: from enigma_common import encode_rotor_10, encode_rotor_26 from enigma_common import n0, n9, nA, nZ def encode_checksum_calc(in_string): """ Calculate the checksum for a given input string. Args: in_string (str): The input string to calculate the checksum for. Returns: None: The function directly calls another function to continue the process. Raises: ValueError: If the input string is not of the expected length. """ key_length = len(in_string) # in_string is a str converting in_string to bytes in m_key_code m_key_code = str.encode(in_string) check_sum = 1 for idx, n in enumerate(m_key_code[2:], 2): if n0 <= n <= n9: temp_sum = n - n0 else: temp_sum = n - nA check_sum += idx + temp_sum + (idx * temp_sum) check_sum = ((100 - check_sum) % 100) dummy = [n0 + (check_sum % 10), n0 + ((check_sum // 10) % 10)] m_key_code = bytes(dummy) + m_key_code[2:] print("DEBUG: Calculated Checksum:", check_sum) print("DEBUG: Modified Key Code with Checksum:", m_key_code) return m_key_code def encode_option_code_calc(m_key_code): """ Calculate the option code based on the modified key code. Args: m_key_code (bytes): The modified key code used for option code calculation. Returns: None: The function calls another function to print the option code. Raises: TypeError: If the input is not in bytes format. """ # Setting max check sum size to 26000 max_check_sum = 26000 # Encipher Key option_key = [] checksum = 0 for idx, n in enumerate(m_key_code[:]): print(f"DEBUG: Original Char: {n}") if n0 <= n <= n9: temp_sum = (n - n0) m_key_code = (encode_rotor_10[(temp_sum + max_check_sum - checksum) % 10] + 0) else: temp_sum = n - nA m_key_code = (encode_rotor_10[(temp_sum + max_check_sum - checksum) % 26] + nA) checksum += idx + temp_sum + (idx * temp_sum) option_key.append(int(m_key_code)) print(f"DEBUG: Transformed Char: {m_key_code}, Checksum: {checksum}") print(f"DEBUG: Original Option Key: {option_key}") return option_keyDecode Functions: # enigma_decode.py from enigma_common import decode_rotor_10, decode_rotor_26 from enigma_common import n0, n9, nA, nZ def decode(encoded_option_code): # Convert the encoded option code to bytes encoded_bytes = bytes(encoded_option_code, 'utf-8') # Validate the checksum if not decode_checksum_calc(encoded_bytes): print("Invalid checksum.") return None, None # Return a tuple of None values # Continue with the decoding process... decoded_data = decode_with_rotor_10(encoded_bytes) original_key = decode_with_rotor_26(decoded_data) # Return the decoded data and the original key return decoded_data, original_key def decode_with_rotor_10(encoded_data): decoded_data = '' checksum = 0 for idx, char in enumerate(encoded_data): str_char = chr(char) # Convert byte to its character representation if str_char.isdigit(): byte_val = ord(str_char) # Convert character to its ASCII value adjusted_val = (byte_val - n0) % 10 # Reverse the transformation decoded_val = decode_rotor_10[adjusted_val] # Adjust for the checksum effect (if applicable) temp_sum = decoded_val checksum += idx + temp_sum + (idx * temp_sum) print(f"DEBUG: idx={idx}, char={char}, byte_va{byte_val}, adjusted_val={adjusted_val}, decoded_val={decoded_val}, temp_sum={temp_sum}, checksum={checksum}") # Add the decoded value to the decoded data decoded_data += str(decoded_val) else: decoded_data += str_char # Non-digit characters are left as is return decoded_data def decode_with_rotor_26(encoded_data): """ Calculate the original key code based on the option key for rotor 26. Args: encoded_data (list): The encoded data used for original key code calculation. Returns: list: The original key code. Raises: TypeError: If the input is not in list format. """ # Setting max check sum size to 26000 max_check_sum = 26000 # Decipher Key original_key = [] checksum = 0 for idx, n in enumerate(encoded_data[:]): if nA <= n <= nZ: temp_sum = n - nA original_key_code = (decode_rotor_26[(temp_sum + max_check_sum - checksum) % 26] + nA) checksum += idx + temp_sum + (idx * temp_sum) original_key.append(int(original_key_code)) return original_key def decode_checksum_calc(encoded_string): """ Validate the checksum for a given encoded string. Args: encoded_string (bytes): The encoded string to validate the checksum for. Returns: bool: True if the checksum is valid, False otherwise. """ # Extract the checksum from the encoded string extracted_checksum = (encoded_string[1] - n0) * 10 + (encoded_string[0] - n0) # Calculate the checksum for the remaining string check_sum = 1 for idx, n in enumerate(encoded_string[2:], 2): if n0 <= n <= n9: temp_sum = n - n0 # Reverse the transformation else: temp_sum = n - nA check_sum += idx + temp_sum + (idx * temp_sum) print(f"DEBUG: idx={idx}, n={n}, temp_sum={temp_sum}, check_sum={check_sum}") # Debug statement check_sum = ((100 - check_sum) % 100) print("DEBUG: Extracted Checksum:", extracted_checksum) print("DEBUG: Calculated Checksum:", check_sum) # Return True if the calculated checksum matches the extracted checksum return check_sum == extracted_checksumRotors: """ This module contains global variables and lists used for encoding and decoding in the Enigma machine. """ n0, n9, nA, nZ = b'09A' # Encode Enigma Rotors 10 & 26 encode_rotor_10 = [5, 4, 1, 8, 7, 3, 0, 2, 9, 6] encode_rotor_26 = [16, 8, 25, 5, 23, 21, 18, 17, 2, 1, 7, 24, 15, 11, 9, 6, 3, 0, 19, 12, 22, 14, 10, 4, 20, 13] # Decode Enigma Rotors 10 & 26 - Inverse of encode decode_rotor_10 = [6, 2, 7, 5, 1, 0, 9, 4, 3, 8] decode_rotor_26 = [17, 9, 8, 16, 23, 3, 15, 10, 1, 14, 22, 13, 19, 25, 21, 12, 0, 7, 6, 18, 24, 5, 20, 4, 11, 2]Encode Debug Output: DEBUG: Calculated Checksum: 48 DEBUG: Modified Key Code with Checksum: b'8469641234567001' DEBUG: Original Char: 56 DEBUG: Transformed Char: 9, Checksum: 8 DEBUG: Original Option Key: [9] DEBUG: Original Char: 52 DEBUG: Transformed Char: 0, Checksum: 17 DEBUG: Original Option Key: [9, 0] DEBUG: Original Char: 54 DEBUG: Transformed Char: 6, Checksum: 37 DEBUG: Original Option Key: [9, 0, 6] DEBUG: Original Char: 57 DEBUG: Transformed Char: 1, Checksum: 76 DEBUG: Original Option Key: [9, 0, 6, 1] DEBUG: Original Char: 54 DEBUG: Transformed Char: 5, Checksum: 110 DEBUG: Original Option Key: [9, 0, 6, 1, 5] DEBUG: Original Char: 52 DEBUG: Transformed Char: 7, Checksum: 139 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7] DEBUG: Original Char: 49 DEBUG: Transformed Char: 1, Checksum: 152 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1] DEBUG: Original Char: 50 DEBUG: Transformed Char: 5, Checksum: 175 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5] DEBUG: Original Char: 51 DEBUG: Transformed Char: 9, Checksum: 210 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9] DEBUG: Original Char: 52 DEBUG: Transformed Char: 7, Checksum: 259 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7] DEBUG: Original Char: 53 DEBUG: Transformed Char: 0, Checksum: 324 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0] DEBUG: Original Char: 54 DEBUG: Transformed Char: 1, Checksum: 407 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0, 1] DEBUG: Original Char: 55 DEBUG: Transformed Char: 5, Checksum: 510 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0, 1, 5] DEBUG: Original Char: 48 DEBUG: Transformed Char: 5, Checksum: 523 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0, 1, 5, 5] DEBUG: Original Char: 48 DEBUG: Transformed Char: 2, Checksum: 537 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0, 1, 5, 5, 2] DEBUG: Original Char: 49 DEBUG: Transformed Char: 7, Checksum: 568 DEBUG: Original Option Key: [9, 0, 6, 1, 5, 7, 1, 5, 9, 7, 0, 1, 5, 5, 2, 7] Option Code: 9061 5715 9701 5527 Would you like to generate another Option Code (Y/N): n OK, goodbye! :-) DECODE Debug Output. Enigma V3.5 Do you want to (E)ncode or (D)ecode? Enter E or D: d Enter the option code to decode: 9061571597015527 DEBUG: idx=2, n=54, temp_sum=6, check_sum=21 DEBUG: idx=3, n=49, temp_sum=1, check_sum=28 DEBUG: idx=4, n=53, temp_sum=5, check_sum=57 DEBUG: idx=5, n=55, temp_sum=7, check_sum=104 DEBUG: idx=6, n=49, temp_sum=1, check_sum=117 DEBUG: idx=7, n=53, temp_sum=5, check_sum=164 DEBUG: idx=8, n=57, temp_sum=9, check_sum=253 DEBUG: idx=9, n=55, temp_sum=7, check_sum=332 DEBUG: idx=10, n=48, temp_sum=0, check_sum=342 DEBUG: idx=11, n=49, temp_sum=1, check_sum=365 DEBUG: idx=12, n=53, temp_sum=5, check_sum=442 DEBUG: idx=13, n=53, temp_sum=5, check_sum=525 DEBUG: idx=14, n=50, temp_sum=2, check_sum=569 DEBUG: idx=15, n=55, temp_sum=7, check_sum=696 DEBUG: Extracted Checksum: 9 DEBUG: Calculated Checksum: 4 Invalid checksum. Decoding failed. 69641234567001 was the number encoded to 9061571597015527; however, it does not decode 9061571597015527 back to 69641234567001. The decode should be able to get back to the original input. This was originally a C++ application where both the encode and decode worked. Now, just the encoding is working. I have to think I am missing something simple, but I do no know where to go. RE: Enigma Decoding Problem - deanhystad - Dec-12-2023 You should post the C++ code so we know what it is supposed to do. What type was the checksum variable in the C++ code? A lot of C checksum algorithms rely on overflow to limit the checksum to 8 bits or 16 bits or whatever. Python does not have fixed size integers, so you need to use modulo or arithmetic and operations to limit the size of the checksum. RE: Enigma Decoding Problem - krisarmstrong - Dec-13-2023 (Dec-12-2023, 07:38 PM)deanhystad Wrote: You should post the C++ code so we know what it is supposed to do. Thank you, and here is the C++ code. I'm not nearly as versed in C+ as I am in Python, and even in Python, I'm a beginner. I know the basics. C++ Code // Filename: enigma.cpp // Original: 6/11/2007 // Revision: 8/15/2007 // // DESCRIPTION: C/C++ program to calculate/check Fluke option key codes. // STOLEN FROM: Peter Oesper (LANMeter), Bruce Kosbab, Jamie Howze (NetTool) // // To Build: Use the free Windows 32-bit Dev-C++ compiler (www.bloodshed.net) // To Run: Enter "enigma" from a DOS command prompt window #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> //#include "enigma.h" #ifndef __ENIGMA_H__ #define __ENIGMA_H__ #include <stdio.h> typedef unsigned short uint16; typedef signed short int16; typedef signed int int32; typedef struct { char szCode[5]; char szAbbr[20]; char szName[30]; } T_ProductInfo; #define SW_VERSION "2.00" #define CODE_NTS2 "3001" #define CODE_ESCOPE "6963" #define CODE_LRPRO "7001" #define CODE_1TAT "7920" T_ProductInfo productTable[] = { CODE_NTS2, "NTs2", "NetTool Series II", CODE_LRPRO, "LRPro", "LinkRunner Pro", CODE_ESCOPE, "Escope/MSv2", "EtherScope/MetroScope" // CODE_1TAT, "OneTouch AT", "OneTouch AT" }; int g_tableSize = sizeof( productTable ) / sizeof( productTable[0] ); class EnigmaC { public: // Encrypt the string pointed to by inString and places the // resulting string at the location pointed to by outString. The // encrpyted string will be the same length as the input string. // RETURNS: 1 == Success // 0 == Failure static int16 encrypt(char *inString, char *outString); // Decrypt the string pointed to by inString and place the // resulting string at the location pointed to by outString. // RETURNS: 1 == Success // 0 == Failure static int16 decrypt(char *inString, char *outString); static bool checkOptionKey(uint16 option, char *key, char *serialStr); }; // added for enigma 2 routines const int16 PRODUCT_CODE_SIZE = 4; const int16 OPTION_CODE_SIZE = 3; const int16 SERIAL_NUMBER_SIZE = 7; const int16 CHECK_SUM_SIZE = 2; const int16 KEY_LENGTH = PRODUCT_CODE_SIZE+OPTION_CODE_SIZE+SERIAL_NUMBER_SIZE+CHECK_SUM_SIZE; const int16 SERIAL_LOCATION = CHECK_SUM_SIZE + PRODUCT_CODE_SIZE; const int16 PRODUCT_LOCATION = CHECK_SUM_SIZE; const int16 OPTION_LOCATION = CHECK_SUM_SIZE + PRODUCT_CODE_SIZE + SERIAL_NUMBER_SIZE; const int MAX_CHECK_SUM = 26000; class Enigma2C{ public: static bool checkOptionKey(uint16 option, char *key); static bool encrypt (char *inString, char *outString); static bool decrypt (char *inString, char *outString); }; #endif // __ENIGMA_H__ /* * NOTE: The only valid values input to these routines are ascii hex values */ /* Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ static int16 rotor[] = { 5, 4,14,11, 1, 8,10,13, 7, 3,15, 0, 2,12, 9, 6 }; #define ROTOR_SIZE (sizeof(rotor)/sizeof(int16)) // enigma 2 stuff static int16 dRotor10[] = { 6,2,7,5,1,0,9,4,3,8 }; static int16 dRotor26[] = { 17, 9, 8,16,23, 3,15,10, 1,14,22,13,19, 25,21,12, 0, 7, 6,18,24, 5,20, 4,11, 2 }; static int16 eRotor10[] = { 5,4,1,8,7,3,0,2,9,6 }; static int16 eRotor26[] = { 16, 8,25, 5,23,21,18,17, 2, 1, 7,24,15, 11, 9, 6, 3, 0,19,12,22,14,10, 4,20,13, }; static char m_keyCode[KEY_LENGTH]; // Encrypt the string pointed to by inString and places the // resulting string at the location pointed to by outString. The // encrpyted string will be the same length as the input string. // RETURNS: 1 == Success // 0 == Failure int16 EnigmaC::encrypt(char *inString, char *outString) { int16 inValue; int16 outValue = 0; int16 index = 0; while (*inString) { int32 TMP_inValue; if (!isxdigit(*inString) || !sscanf (inString++, "%1x", &TMP_inValue)) return 0; // Illegal input value inValue = TMP_inValue; // Do the encryption - table lookup XORed with last output outValue = (rotor[(inValue + index) % ROTOR_SIZE]) ^ outValue; // Output the result as a string sprintf(outString++, "%1x", outValue); index++; } return 1; } // Decrypt the string pointed to by inString and place the // resulting string at the location pointed to by outString. // RETURNS: 1 == Success // 0 == Failure int16 EnigmaC::decrypt(char *inString, char *outString) { int16 inValue; int16 outValue; int16 oldOut; int16 xorValue = 0; int16 index = 0; int16 temp; while (*inString) { int32 TMP_oldOut; if (!isxdigit(*inString) || !sscanf(inString++, "%1x", &TMP_oldOut)) return 0; // Illegal input value oldOut = TMP_oldOut; //printf( "oldOut= %x\n", oldOut ); // DEBUG only // Reverse the encryption inValue = oldOut ^ xorValue; for (outValue = 0; outValue < ROTOR_SIZE; outValue++) if (rotor[outValue] == inValue) break; // Output the result as a string temp = (outValue - index) % ROTOR_SIZE; sprintf(outString++, "%1x", temp); xorValue = oldOut; index++; } return 1; } // Validate the key for the option bool EnigmaC::checkOptionKey(uint16 option, char *key, char *serialStr) { // NULL keys are invalid if (!key || strlen(key) == 0) return false; // Check for the secret master override if (strcmp(key, "bladerules") == 0) return true; // See if the key matches the desired option and MAC. char dStr[20]; int16 sucess = EnigmaC::decrypt(key, dStr); // serial = bytes 0..9 // Option # = bytes 10..11 if (sucess) { // Compare the Serial Number char s[20]; int i, j; for (i = 11, j = 0; i > 1; j++, i--) s[j] = dStr[i]; if (strncmp(serialStr, s, 10)) return false; // Compare the option dStr[2] = 0; int o = strtol(dStr, NULL, 10); if (o != option) return false; return true; } return false; } /////////////////////////////////////////////////////// /// ENIGMA 2 routines /////////////////////////////////////////////////////// // Validate the key for the option bool Enigma2C::checkOptionKey(uint16 option, char *key) { // NULL keys are invalid if (!key || strlen(key) == 0) return false; // Decode the key char dStr[20]; int success = Enigma2C::decrypt(key, dStr); // return value // checksum = bytes 0-1 // product code = bytes 2-5 // serial # = bytes 6-12 // option # = bytes 13-15 if (success) { // Compare the serial number (ignore the leading 3 zeroes) #if 0 if (strncmp(ComPrcsC::sysInfo.serial + 3, dStr + SERIAL_LOCATION, 7)) #endif return false; // Compare the option int16 o = strtol(dStr + OPTION_LOCATION, NULL, 10); if (o != option) return false; return true; } return false; } bool Enigma2C::decrypt(char *inString, char *outString) { int16 checksum = 0; int16 tmpSum = 0; strcpy(m_keyCode, inString); // Decipher key. for (int16 i = 0; i < KEY_LENGTH; i++) { if (m_keyCode[i] >= 'A') { tmpSum = (dRotor26[m_keyCode[i] - 'A'] + checksum) % 26; m_keyCode[i] = tmpSum + 'A'; } else { tmpSum = (dRotor10[m_keyCode[i] - '0'] + checksum) % 10; m_keyCode[i] = tmpSum + '0'; } // printf( "DEBUG> m_keyCode[%02x]= %02x\n", i, m_keyCode[i] ); checksum += i + tmpSum + (i * tmpSum); } strcpy(outString, m_keyCode); // Return true if checksum okay. checksum += (8 * (m_keyCode[1] - '0')); return ((checksum % 100) == 0); } bool Enigma2C::encrypt(char *inString, char *outString) { int16 csum = 1, checksum = 0; int16 tmpSum = 0; int16 i =0; strcpy(m_keyCode, inString); // Calculate and store 2-digit checksum. for (i = 2; i < KEY_LENGTH; i++){ if (isdigit(m_keyCode[i])){ tmpSum = m_keyCode[i] - '0'; } else { tmpSum = m_keyCode[i] - 'A'; } csum += i + tmpSum+ (i * tmpSum); } csum = 100 - (csum % 100); m_keyCode[0] = '0' + (csum % 10); m_keyCode[1] = '0' + ((csum / 10) % 10); // Encipher key checksum = 0; for (i = 0; i < KEY_LENGTH; i++){ if (isdigit(m_keyCode[i])){ tmpSum = m_keyCode[i] - '0'; m_keyCode[i] = eRotor10[(tmpSum + MAX_CHECK_SUM - checksum) % 10] + '0'; } else { tmpSum = m_keyCode[i] - 'A'; m_keyCode[i] = eRotor26[(tmpSum + MAX_CHECK_SUM - checksum) % 26] + 'A'; } checksum += i + tmpSum + (i * tmpSum); } strcpy(outString, m_keyCode); return true; } void printOptKey( char *optString ) { printf( "Option Key:" ); for ( int k = 0; k < strlen(optString); k++ ) { if ( k % 4 == 0 ) { printf( " " ); } printf( "%c", optString[k] ); } printf( "\n" ); } void calcNetToolClassicOptionKey(char *serialStr, int optionNum) { // Original NetTool -- Calculate Option Key char szLine[100] = ""; // default for Enigma 1 char optionStr[1+1] = "4"; // 1 digit option number if ( strlen(serialStr) == 0 ) { int numChars = 0; do { printf( "Enter Serial Number (10 digits): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); numChars = strlen(szLine); szLine[10] = 0; strcpy( serialStr, szLine ); } while ( numChars != (10+1) ); // allow for newline } else { // truncate serial number string to 10 digits serialStr[10] = 0; } if ( optionNum < 0 ) { printf( "\n" ); printf( "NetTool Options: 0=Inline 1=Reports/Ping 3=Personal 4=VoIP 5=SwitchWizard\n" ); printf( "Enter Option Number (1 digit): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[1] = 0; optionNum = atoi(szLine); } if ( optionNum < 0 || optionNum > 9 ) // option must be a single digit { optionNum = 0; } sprintf( optionStr, "%d", optionNum ); char inString[12+1] = ""; sprintf( inString, "%s%s%s", serialStr, optionStr, "0" ); // reverse the string char revString[20] = ""; int i, j; for (i = 11, j = 0; i >= 0; j++, i--) { revString[j] = inString[i]; } // printf( "inString: %s\n", inString ); // DEBUG only // printf( "revString: %s\n", revString ); // DEBUG only char outString[100] = ""; printf( "\n" ); printf( "Encrypting with Enigma 1...\n" ); EnigmaC::encrypt(revString, outString); //printf( "DEBUG> serialStr: %s (must be 10 digits)\n", serialStr ); //printf( "DEBUG> optionNum: %s\n", optionStr ); //printf( "DEBUG> optionKey: %s\n", outString ); printOptKey( outString ); } void checkNetToolClassicOptionKey(char *optionKeyStr) { // Original NetTool -- Check Option Key char szLine[100] = ""; // default for Enigma 1 char serialStr[10+1] = "0003333016"; // 10 digit serial number // valid key test char inString[12+1] = "5dabade112dd"; // option #04 for s/n 0003333016 uint16 optionNum = 4; // VoIP option (NetTool Series II) do { printf( "Enter Serial Number (10 digits): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[10] = 0; strcpy( serialStr, szLine ); } while ( strlen(serialStr) != 10 ); if ( strlen(optionKeyStr) == 12 ) { strcpy( inString, optionKeyStr ); } else { do { printf( "Enter Option Key (12 digits): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[12] = 0; strcpy( inString, szLine ); } while ( strlen(inString) != 12 ); } printf( "Enter Option Number (1 digit): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[1] = 0; int nOption = atoi(szLine); if ( nOption < 0 || nOption > 9 ) { nOption = 0; } optionNum = (uint16) nOption; printf( "\n" ); printf( "EnigmaC::checkOptionKey()...\n" ); printf( "serialNum: %s\n", serialStr ); printf( "optionKey: %s\n", inString ); printf( "optionNum: %x\n", optionNum ); if ( EnigmaC::checkOptionKey(optionNum, inString, serialStr) ) { printf( "Option valid\n" ); } else { printf( "Option invalid\n" ); } } void calcEnigma2OptionKey(char *serialStr, int optionNum, int productCode, bool bAssumeEscope) { // NetTool Series II -- Calculate Option Key char szLine[100] = ""; char outString[100] = ""; // 2 char checksum + 4 char productID + 7 char S/N + 3 char option char inString[] = "ccppppsssssssooo"; // checksum, product code, s/n, option char szProductCode[4+1] = CODE_NTS2; char optionStr[3+1] = "003"; // 1 digit option number int k = 0; if ( strlen(serialStr) == 0 ) { int numChars = 0; do { printf( "Enter Serial Number (7 digits): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); numChars = strlen(szLine); szLine[7] = 0; strcpy( serialStr, szLine ); } while ( numChars != (7+1) ); // allow for newline } else { // command line parameter serialStr[7] = 0; // truncate serial number string to 7 digits printf( "SerialNum= %s\n", serialStr ); } if ( optionNum < 0 ) { printf( "Enter Option # (3 digits max. 4=NTs2_VoIP 7=EScope_All, 2=LR_Reflect, 31=MSv2_All): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[3] = 0; optionNum = atoi(szLine); if ( szLine[0] == '\n' ) { if ( bAssumeEscope ) { printf( "Assuming EtherScope LAN/WLAN option 7 \n\n" ); optionNum = 7; } else { printf( "Assuming LinkRunner Pro Reflector option 2 \n\n" ); optionNum = 2; } } } else { // command line parameter printf( "OptionNum= %d\n", optionNum ); } sprintf( optionStr, "%03d", optionNum ); if ( productCode < 0 ) { //printf( "Enter Product Code (4 digits. 3001=NTs2 6963=EScope, 7001=LRPro): " ); printf( "Enter Product Code (4 digits. " ); for ( k = 0; k < g_tableSize; k++ ) { printf( "%s=%s", productTable[k].szCode, productTable[k].szAbbr); if ( k < g_tableSize - 1 ) { printf( " " ); } } printf( "): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); szLine[4] = 0; productCode = atoi(szLine); if ( productCode == 0 ) { if ( bAssumeEscope ) { printf( "Assuming EtherScope product code %s\n", CODE_ESCOPE ); productCode = atoi(CODE_ESCOPE); } else { printf( "Assuming NetTool Series II product code %s\n", CODE_NTS2 ); productCode = atoi(CODE_NTS2); } } } else { // command line parameter printf( "Product= " ); for ( k = 0; k < g_tableSize; k++ ) { if ( productCode == atoi(productTable[k].szCode) ) { printf( "%s", productTable[k].szName ); break; } } if ( k == g_tableSize ) { printf( "%d", productCode ); } printf( "\n" ); } sprintf( szProductCode, "%04d", productCode ); strcpy( inString, "0000000000000000" ); memcpy( inString+2, szProductCode, 4 ); memcpy( inString+2+4, serialStr, 7 ); memcpy( inString+2+4+7, optionStr, 3 ); //printf( "DEBUG> inString: %s\n", inString ); printf( "\n" ); printf( "Encrypting with Enigma 2...\n" ); Enigma2C::encrypt(inString, outString); //printf( "Option Key: %s\n", outString ); printOptKey( outString ); } void checkEnigma2OptionKey(char *optionKeyStr) { // NetTool Series II -- Check Option Key // test case // OptionKey= "6406257948597747"; // 16 digit key code from EtherScope // ProductCode= 6963 -> EtherScope // SerialNumber= 0000607 // OptionNumber= 007 char szLine[100] = ""; char inString[16+1] = "aaaabbbbccccdddd"; // 16 digit option key char outString[100] = ""; int k = 0; if ( strlen(optionKeyStr) == 16 ) { strcpy( inString, optionKeyStr ); } else { int numChars = 0; do { printf( "Enter Option Key (16 digits): " ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); numChars = strlen(szLine); szLine[16] = 0; strcpy( inString, szLine ); } while ( numChars != (16+1) ); // allow for newline } printf( "Decrypting with Enigma 2...\n" ); Enigma2C::decrypt(inString, outString); char szProductCode[4+1] = ""; memcpy(szProductCode, outString+2, 4); printf( "Product Code: %s -> ", szProductCode ); // perform lookup in product table for ( k = 0; k < g_tableSize; k++ ) { if ( strcmp(szProductCode, productTable[k].szCode) == 0 ) { printf( "%s", productTable[k].szName ); break; } } if ( k == g_tableSize ) { printf( "Unknown" ); } printf( "\n" ); char szSerialNum[7+1] = ""; memcpy(szSerialNum, outString+2+4, 7); printf( "SerialNumber: %s\n", szSerialNum ); char szOptionNum[3+1] = ""; memcpy(szOptionNum, outString+2+4+7, 3); printf( "OptionNumber: %s\n", szOptionNum ); } int main(int argc, char *argv[]) { char szLine[100] = ""; int selection = 0; // 10 digit serial number for Original NetTool // 7 digit serial number for NetTool Series II char serialStr[10+1] = ""; char optionKeyStr[16+1] = ""; // for EtherScope/NetTool Series II int optionNum = -1; // 3 digits max int productCode = -1; // 4 digits max bool bAssumeEscope = false; bool bPromptToExit = true; // handle command line arguments if ( argc > 1 ) { if ( strcmp("?", argv[1]) == 0 || strcmp("-?", argv[1]) == 0 ) { // show usage printf( "usage: %s [-d|-e|-n|-x] [optionKey|serialNo] [optionNo] [productCode]\n", argv[0] ); printf( "where, \n" ); printf( "-d is decrypt EtherScope option key \n" ); printf( "-e is encrypt EtherScope option key \n" ); printf( "-l is encrypt LinkRunner Pro option key \n" ); printf( "-n is calculate NetTool option key \n" ); printf( "-x is check NetTool option key \n" ); return 1; } else if ( strcmp("-n", argv[1]) == 0 ) { // encrypt for Original NetTool selection = 1; } else if ( strcmp("-x", argv[1]) == 0 ) { // check Original NetTool option key selection = 2; } else if ( strcmp("-e", argv[1]) == 0 ) { // encrypt for EtherScope selection = 3; productCode = atoi(CODE_ESCOPE); bAssumeEscope = true; } else if ( strcmp("-l", argv[1]) == 0 ) { // encrypt for LinkRunner Pro selection = 3; // encrypt productCode = atoi(CODE_LRPRO); // LinkRunner Pro } else if ( strcmp("-d", argv[1]) == 0 ) { // decrypt for other Fluke products (see table) selection = 4; } else { selection = atoi(argv[1]); } if ( argc > 2 ) { if ( selection == 4 ) { strncpy(optionKeyStr, argv[2], 16); } else if ( selection == 2 ) { strncpy(optionKeyStr, argv[2], 12); } else { // selection is 1 or 3 strncpy(serialStr, argv[2], 10); if ( argc > 3 ) { optionNum = atoi(argv[3]); if ( argc > 4 ) { productCode = atoi(argv[4]); bPromptToExit = false; } } } } } while ( selection < 1 || selection > 4 ) { printf( "\n" ); printf( "Enter selection: \n" ); printf( "1. Calculate option key for NetTool 10/100\n" ); printf( "2. Check option key for NetTool 10/100\n" ); printf( "3. Calculate option key for other Fluke products\n" ); printf( "4. Check option key for other Fluke products\n" ); strcpy( szLine, "" ); fgets( szLine, sizeof(szLine), stdin ); selection = atoi(szLine); } printf( "\n" ); if ( !bPromptToExit ) { //printf( "Selection= %d\n", selection ); } switch ( selection ) { case 1: // calculate option key for original NetTool calcNetToolClassicOptionKey(serialStr, optionNum); break; case 2: // check option key for Original NetTool checkNetToolClassicOptionKey(optionKeyStr); break; case 3: // encrypt option key for other Fluke products (see table) calcEnigma2OptionKey(serialStr, optionNum, productCode, bAssumeEscope); break; case 4: // decrypt option key for other Fluke products (see table) checkEnigma2OptionKey(optionKeyStr); break; default: printf( "invalid selection\n" ); break; } printf( "\n" ); if ( bPromptToExit ) { fprintf( stderr, "Press Enter key to exit\n" ); getchar(); } return 0; } // end-of-file RE: Enigma Decoding Problem - deanhystad - Dec-13-2023 Prune that down to the relevant C++ code. Your decode checsum calc looks nothing like this: bool Enigma2C::decrypt(char *inString, char *outString) { int16 checksum = 0; int16 tmpSum = 0; strcpy(m_keyCode, inString); // Decipher key. for (int16 i = 0; i < KEY_LENGTH; i++) { if (m_keyCode[i] >= 'A') { tmpSum = (dRotor26[m_keyCode[i] - 'A'] + checksum) % 26; m_keyCode[i] = tmpSum + 'A'; } else { tmpSum = (dRotor10[m_keyCode[i] - '0'] + checksum) % 10; m_keyCode[i] = tmpSum + '0'; } // printf( "DEBUG> m_keyCode[%02x]= %02x\n", i, m_keyCode[i] ); checksum += i + tmpSum + (i * tmpSum); } strcpy(outString, m_keyCode); // Return true if checksum okay. checksum += (8 * (m_keyCode[1] - '0')); return ((checksum % 100) == 0); }I modified your decode function to look like this: def decode(encoded_option_code): # Convert the encoded option code to bytes encoded_bytes = bytes(encoded_option_code, "utf-8") # Continue with the decoding process... return decode_with_rotor_10(encoded_bytes)This decodes the message correctly. I don't think you can compute the checksum without also decoding the message. It is a single step process, not a two-step process. You can either modify the decode function so it returns a success/fail status, or you can raise a checksum exception RE: Enigma Decoding Problem - Larz60+ - Dec-14-2023 You might be interested in this old enigma thread. |