From ccfaaf39f8e8fd3b14f7e89759372ec0f3b25cd1 Mon Sep 17 00:00:00 2001 From: mvvasilev Date: Mon, 28 Oct 2024 00:05:33 +0200 Subject: [PATCH] Finish Challenge 1 --- README.md | 5 ++ go.mod | 3 ++ set1/challenge_1.go | 123 ++++++++++++++++++++++++++++++++++++++++++++ test/set_1_test.go | 19 +++++++ 4 files changed, 150 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 set1/challenge_1.go create mode 100644 test/set_1_test.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc443af --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# cryptopals + +Exercises in cryptography from https://cryptopals.com + +The goal is to do each challenge with no imports from the Go stdlib. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..94fae72 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module mvvasilev.dev/cryptopals + +go 1.23.2 diff --git a/set1/challenge_1.go b/set1/challenge_1.go new file mode 100644 index 0000000..49ab843 --- /dev/null +++ b/set1/challenge_1.go @@ -0,0 +1,123 @@ +package set1 + +const Base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +const Base64PaddingCharacter = "=" + +// NOTE: Unused +func HexDecode(hex string) (value string, success bool) { + size := len(hex) + + var hexValues = map[byte]byte{ + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + 'a': 10, + 'b': 11, + 'c': 12, + 'd': 13, + 'e': 14, + 'f': 15, + } + + if size%2 != 0 { + return "", false + } + + buffer := make([]byte, 0, size/2) + + for i := 0; i < size; i += 2 { + first := hexValues[hex[i]] << 4 + second := hexValues[hex[i+1]] + + buffer = append(buffer, first^second) + } + + return string(buffer), true +} + +// NOTE: Unused +func Base64Encode(value string) (base64 string) { + originalBytes := []byte(value) + size := len(originalBytes) + + buffer := make([]byte, 0, size+size/3) + + for i := 0; i < size; i += 3 { + + // TODO: Handle end case to add padding + + originals := originalBytes[i : i+3] + + first := originals[0] >> 2 + second := (0b00110000 & (originals[0] << 4)) ^ (originals[1] >> 4) + third := (0b00111100 & (originals[1] << 2)) ^ (originals[2] >> 6) + fourth := 0b00111111 & originals[2] + + buffer = append(buffer, Base64Alphabet[first], Base64Alphabet[second], Base64Alphabet[third], Base64Alphabet[fourth]) + } + + return string(buffer) +} + +func HexToBase64(hexValue string) (base64 string, success bool) { + hexSize := len(hexValue) + + var hexValues = map[byte]byte{ + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + 'a': 10, + 'b': 11, + 'c': 12, + 'd': 13, + 'e': 14, + 'f': 15, + } + + if hexSize%2 != 0 { + return "", false + } + + plainBuffer := make([]byte, 0, hexSize/2) + + for i := 0; i < hexSize; i += 2 { + first := hexValues[hexValue[i]] << 4 + second := hexValues[hexValue[i+1]] + + plainBuffer = append(plainBuffer, first^second) + } + + plainSize := len(plainBuffer) + + base64Buffer := make([]byte, 0, plainSize+plainSize/3) + + for i := 0; i < plainSize; i += 3 { + + // TODO: Handle end case to add padding + + originals := plainBuffer[i : i+3] + + first := originals[0] >> 2 + second := (0b00110000 & (originals[0] << 4)) ^ (originals[1] >> 4) + third := (0b00111100 & (originals[1] << 2)) ^ (originals[2] >> 6) + fourth := 0b00111111 & originals[2] + + base64Buffer = append(base64Buffer, Base64Alphabet[first], Base64Alphabet[second], Base64Alphabet[third], Base64Alphabet[fourth]) + } + + return string(base64Buffer), true +} diff --git a/test/set_1_test.go b/test/set_1_test.go new file mode 100644 index 0000000..7b5d312 --- /dev/null +++ b/test/set_1_test.go @@ -0,0 +1,19 @@ +package cryptopals_test + +import ( + "testing" + + "mvvasilev.dev/cryptopals/set1" +) + +const Challenge1HexValue = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d" + +func Test_Challenge1(t *testing.T) { + const expected = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t" + + value, success := set1.HexToBase64(Challenge1HexValue) + + if !success || value != expected { + t.Fatal("Set 1, Challenge 1 has failed") + } +}