czwartek, 17 lipca 2025

Cryptopals - 1/2 - Fixed XOR

W tym poście chciałbym opisać rozwiązania zadania Fixed XOR z Cryptopals.


Zadanie polega na wynik z poprzedniego zadania zastosować XOR:

  1. 1c0111001f010100061a024b53535009181c
  2. XOR
  3. 686974207468652062756c6c277320657965
  4. Wynik:
  5. 746865206b696420646f6e277420706c6179

Poprawność zadania można zweryfikować przez wprowadzenie danych do narzędzia online:

Zacznę od programu w Pythonie.

Python:


Najprościej wprowadzić dane jako ciągi liczb w postaci HEX, co wygląda mniej więcej tak:

  1. a = 0x1c0111001f010100061a024b53535009181c
  2. b = 0x686974207468652062756c6c277320657965
  3. print(hex(a ^ b))

W przypadku gdy dane wejściowe są wprowadzane jako ciągi znaków, to należy zastosować konwersję:

  1. a_str = "1c0111001f010100061a024b53535009181c"
  2. b_str = "686974207468652062756c6c277320657965"
  3. a = int(a_str, 16)
  4. b = int(b_str, 16)
  5. result = a ^ b
  6. print(hex(result)[2:])

C:


Język C nie pozwala na przechowywanie tak dużych danych w postaci jednej zmiennej. Więc należy zastosować tablicę i przechodzić XOR po każdym bajcie danych. Dokładnie to samo robi Python, tylko użytkownik załatwia te operacje jedną instrukcją. Tutaj trzeba się nieco więcej opisać. 

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. int main() {
  6.     unsigned char a[] = {
  7.         0x1c, 0x01, 0x11, 0x00, 0x1f, 0x01, 0x01, 0x00,
  8.         0x06, 0x1a, 0x02, 0x4b, 0x53, 0x53, 0x50, 0x09,
  9.         0x18, 0x1c
  10.     };
  11.  
  12.     unsigned char b[] = {
  13.         0x68, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20,
  14.         0x62, 0x75, 0x6c, 0x6c, 0x27, 0x73, 0x20, 0x65,
  15.         0x79, 0x65
  16.     };
  17.  
  18.     size_t len = sizeof(a);
  19.     unsigned char result[len];
  20.  
  21.     for (size_t i = 0; i < len; ++i) {
  22.         result[i] = a[i] ^ b[i];
  23.     }
  24.  
  25.     printf("0x");
  26.     for (size_t i = 0; i < len; ++i) {
  27.         printf("%02x", result[i]);
  28.     }
  29.     printf("\n");
  30.  
  31.     return 0;
  32. }

GO:

Poniżej jeszcze rozwiązania w języku GO:

  1. package main
  2.  
  3. import "fmt"
  4.  
  5. func main() {
  6.     a := []byte{
  7.         0x1c, 0x01, 0x11, 0x00, 0x1f, 0x01, 0x01, 0x00,
  8.         0x06, 0x1a, 0x02, 0x4b, 0x53, 0x53, 0x50, 0x09,
  9.         0x18, 0x1c,
  10.     }
  11.  
  12.     b := []byte{
  13.         0x68, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20,
  14.         0x62, 0x75, 0x6c, 0x6c, 0x27, 0x73, 0x20, 0x65,
  15.         0x79, 0x65,
  16.     }
  17.  
  18.     if len(a) != len(b) {
  19.         return
  20.     }
  21.  
  22.     result := make([]byte, len(a))
  23.  
  24.     for i := 0; i < len(a); i++ {
  25.         result[i] = a[i] ^ b[i]
  26.     }
  27.  
  28.     fmt.Print("0x")
  29.     for _, val := range result {
  30.         fmt.Printf("%02x", val)
  31.     }
  32.     fmt.Println()
  33. }