Threefish selber implementieren
-
Ich habe nur mal schnell drübergeschaut:
-
Der Code ist falsch. Der Parametervoid decrypt(unsigned nwords, u64 plaintext[], u64 ciphertext[]) { u8 key[nwords] = "haallo";
nwords
gehört per se nicht zukey
. Wennnwords
größer ist als 6, greifst du auf nicht initialisierten Speicher zu. - Wo ist dein Key Schedule? Mir fehlt da die Konstante C = 0x1BD11BD...
- Sollte der Key nicht als Parameter übergeben werden?
- Verwende Zeiger nur dann, wenn du diese unbedingt benötigst. Bei der Funktion
mix
z.B. würde auch eine Referenz genügen. - Lerne Const Correctness. Was konstant ist, kann man versehentlich nicht ändern.
- Verwende bitte kein VLA. Visual Studio mag diese nicht.
- Achte bitte auf sorgsame Typ-Definitionen. Nichts ist schlimmer als eine undokumentiertes
char Flags
.- Deine
unsigned
Variablen sollten vermutlich vom Typsize_t
sein. - Entspricht u64 nicht eigentlich einem Block? Wie sieht das Padding aus? (Stichwort OPENSSL_PKCS1_PADDING)
- Warum machst du das
typedef uint64_t u64;
?
- Deine
- Wo sind die Testreihen? Kryptographie ist eine hochkritisches Stück Software, welches sorgfältig getestet werden muss. Erfüllt deine Software die Testvektoren (https://github.com/weidai11/cryptopp/blob/master/TestVectors/threefish.txt) ?
-
-
@Quiche-Lorraine sagte in Threefish selber implementieren:
Der Code ist falsch. Der Parameter nwords gehört per se nicht zu key. Wenn nwords größer ist als 6, greifst du auf nicht initialisierten Speicher zu.
Wo ist dein Key Schedule? Mir fehlt da die Konstante C = 0x1BD11BD...
Sollte der Key nicht als Parameter übergeben werden?Danke, ich denke, daran wird es liegen.
Den Key hatte ich zum Testen erst mal fest "einprogrammiert"... Kann später noch mal schauen.
-
@EinNutzer0 sagte in Threefish selber implementieren:
Den Key hatte ich zum Testen erst mal fest "einprogrammiert"... Kann später noch mal schauen.
Zum Testen gibt es Unit Tests. Wennn man sich an Kryptographie begibt, gibt es Dinge die man nicht macht - z.B. Keys oder Zertifikate fest einprogrammieren, auch nicht "nur zum test". Hinterher bleiben die drinnen und man hat die in Produktionscode. Wäre nicht das erste mal.
-
Vielleicht hat hier jemand eine Idee - oder sieht etwas, was ich nicht sehe...
#include <cstdint> #include <cstring> #include <iostream> #include <sstream> using namespace std; typedef uint8_t u8; typedef uint64_t u64; size_t get_min_array_size(size_t min_size) { while (min_size == 0 || min_size % 8 != 0) { min_size++; } return min_size / 8; } void string_to_u64_array(size_t min_array_size, string s, u64 a[]) { string s2 = ""; for (size_t i = 0; i < min_array_size * 8; i++) { s2 += s[i % s.size()]; } for (size_t i = 0; i < min_array_size; i++) { for (size_t j = 0; j < 8; j++) { a[i] <<= 8; a[i] |= (u8)s[i * 8 + j]; } } } string u64_array_to_string(size_t array_size, u64 a[]) { string s = ""; for (size_t i = 0; i < array_size; i++) { u64 b = a[i]; s += (char)(u8)b; // for (size_t j = 0; j < 8; j++) // { // s += (u8)b; // b >>= 8; // } } return s; } u64 rl64(u64 x, u8 r) { return (x << (r & 63)) | (x >> (64 - (r & 63))); } u64 rr64(u64 x, u8 r) { return (x >> (r & 63)) | (x << (64 - (r & 63))); } void mix(u64 a, u64 b, u64 *c, u64 *d, u8 r) { u64 tmp = a + b; *d = rl64(b, r) ^ tmp; *c = tmp; } void mixinv(u64 c, u64 d, u64 *a, u64 *b, u8 r) { u64 tmp = rr64(c ^ d, r); *a = c - tmp; *b = tmp; } void threefish_round(unsigned nwords, u64 v[], u8 r[], u8 p[]) { for (unsigned w = 0; w < nwords; w += 2) { mix(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void threefish_roundinv(unsigned nwords, u64 v[], u8 r[], u8 p[]) { for (unsigned w = 0; w < nwords; w += 2) { mixinv(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void encrypt(unsigned nwords, u64 plaintext[], u64 ciphertext[], string key) { size_t min_size = get_min_array_size(nwords); u64 xkey[min_size + 1] = {0}; cout << "7" << endl; string_to_u64_array(min_size, key, xkey); cout << "8" << endl; unsigned nrounds = 72; u8 rot[8][2] = { {14, 16}, {52, 57}, {23, 40}, {5, 37}, {25, 33}, {46, 12}, {58, 22}, {32, 32}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 subkeys[nrounds / 4 + 1][nwords]; u64 tweak[2] = {0}; u64 xtweak[3] = {tweak[0], tweak[1], tweak[0] ^ tweak[1]}; // expand the key for (unsigned i = 0; i < nrounds / 4 + 1; i++) { for (unsigned w = 0; w < nwords; w++) { subkeys[i][w] = xkey[(i + w) % (nwords + 1)]; } subkeys[i][nwords - 3] += xtweak[i % 3]; subkeys[i][nwords - 2] += xtweak[(i + 1) % 3]; subkeys[i][nwords - 1] += i; } u64 v[nwords]; for (unsigned w = 0; w < nwords; w++) { v[w] = plaintext[w]; } for (unsigned n = 0; n < nrounds; n += 8) { for (unsigned w = 0; w < nwords; w++) { v[w] += subkeys[n / 4][w]; } threefish_round(nwords, v, rot[(n + 0) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 3) % 8], perm[3]); for (unsigned w = 0; w < nwords; w++) { v[w] += subkeys[n / 4 + 1][w]; } threefish_round(nwords, v, rot[(n + 4) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 7) % 8], perm[3]); } for (unsigned w = 0; w < nwords; w++) { ciphertext[w] = v[w] + subkeys[nrounds / 4][w]; } } void decrypt(unsigned nwords, u64 plaintext[], u64 ciphertext[], string key) { size_t min_size = get_min_array_size(nwords); u64 xkey[min_size + 1] = {0}; cout << "9" << endl; string_to_u64_array(min_size, key, xkey); cout << "10" << endl; unsigned nrounds = 72; u8 rot[8][2] = { {14, 16}, {52, 57}, {23, 40}, {5, 37}, {25, 33}, {46, 12}, {58, 22}, {32, 32}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 subkeys[nrounds / 4 + 1][nwords]; u64 tweak[2] = {0}; u64 xtweak[3] = {tweak[0], tweak[1], tweak[0] ^ tweak[1]}; // expand the key for (unsigned i = 0; i < nrounds / 4 + 1; i++) { for (unsigned w = 0; w < nwords; w++) { subkeys[i][w] = xkey[(i + w) % (nwords + 1)]; } subkeys[i][nwords - 3] += xtweak[i % 3]; subkeys[i][nwords - 2] += xtweak[(i + 1) % 3]; subkeys[i][nwords - 1] += i; } u64 v[nwords]; for (unsigned w = 0; w < nwords; w++) { v[w] = ciphertext[w] - subkeys[nrounds / 4][w]; } for (unsigned n = nrounds; n > 0;) { n -= 8; threefish_roundinv(nwords, v, rot[(n + 7) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 4) % 8], perm[0]); for (unsigned w = 0; w < nwords; w++) { v[w] -= subkeys[n / 4 + 1][w]; } threefish_roundinv(nwords, v, rot[(n + 3) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 0) % 8], perm[0]); for (unsigned w = 0; w < nwords; w++) { v[w] -= subkeys[n / 4][w]; } } for (unsigned w = 0; w < nwords; w++) { plaintext[w] = v[w]; } } void encrypt_string(string s, u64 ciphertext[]) { size_t min_size = get_min_array_size(s.size()); u64 plaintext[min_size + 1] = {0}; cout << "1" << endl; string_to_u64_array(min_size, s, plaintext); cout << "2" << endl; encrypt(s.size(), plaintext, ciphertext, "hallo"); cout << "3" << endl; } string decrypt_string(unsigned n1, u64 ciphertext[]) { size_t min_size = get_min_array_size(n1); u64 plaintext[n1 + 1] = {0}; cout << "4" << endl; decrypt(n1, plaintext, ciphertext, "hallo"); cout << "5" << endl; string r = u64_array_to_string(n1, plaintext); cout << "6" << endl; return r; } int main() { string s1 = "Moinnn"; u64 ciphertext[s1.size() + 1] = {0}; cout << s1 << endl; encrypt_string(s1, ciphertext); string s2 = decrypt_string(s1.size(), ciphertext); cout << s2 << endl; return 0; }
Die Ausgabe ist bei mir:
./a.out Moinnn 1 2 7 8 3 4 9 10 5 6 m��s��
Ich würde mich sehr ärgern, wenn jetzt einfach nur ein Konvertierungsfehler von u64 nach char dabei ist...
-
Was soll denn Zeile 43
s += (char)(u8)b;
deiner Meinung nach tun?
-
@Th69 sagte in Threefish selber implementieren:
Was soll denn Zeile 43
s += (char)(u8)b;
deiner Meinung nach tun?Das weiß ich nicht, ich sitze jetzt mehrere Stunden davor und hab den Überblick verloren.
-
Wie von @Schlangenmensch vorgeschlagen, solltest du hier Unit Tests verwenden (so kannst du jede Funktion einzeln auf Korrektheit überprüfen lassen).
-
Könnt ihr mir sagen, woher hier diese verdammten, zufälligen Ausgaben herkommen? Ich initialisiere doch jedes Array mit 0. Bei jedem Starten des Programms gibt es eine andere Ausgabe...
#include <cstdint> #include <cstring> #include <iostream> #include <sstream> using namespace std; typedef uint8_t u8; typedef uint64_t u64; size_t get_min_array_size(size_t min_size) { while (min_size == 0 || min_size % 8 != 0) { min_size++; } return min_size / 8; } void string_to_u64_array(size_t min_array_size, string s1, u64 a[]) { string s2 = ""; for (size_t i = 0; i < min_array_size * 8; i++) { s2 += s1[i % s1.size()]; } for (size_t i = 0; i < min_array_size; i++) { a[i] = 0; for (size_t j = 0; j < 8; j++) { a[i] <<= 8; a[i] |= (u8)s2[i * 8 + j]; } } } string u64_array_to_string(size_t min_array_size, u64 a[]) { string s = ""; for (size_t i = 0; i < min_array_size; i++) { u64 t = a[i]; for (size_t j = 0; j < 8; j++) { s += (u8)t; t >>= 8; } } return s; } u64 rl64(u64 x, u8 r) { return (x << (r & 63)) | (x >> (64 - (r & 63))); } u64 rr64(u64 x, u8 r) { return (x >> (r & 63)) | (x << (64 - (r & 63))); } void mix(u64 a, u64 b, u64 *c, u64 *d, u8 r) { u64 tmp = a + b; *d = rl64(b, r) ^ tmp; *c = tmp; } void mixinv(u64 c, u64 d, u64 *a, u64 *b, u8 r) { u64 tmp = rr64(c ^ d, r); *a = c - tmp; *b = tmp; } void threefish_round(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mix(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void threefish_roundinv(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mixinv(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[(w / 2 + 1) % 2]); } } void encrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], string key) { u64 xkey[nwords] = {0}; string_to_u64_array(nwords, key, xkey); size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 v[nwords] = {0}; for (size_t w = 0; w < nwords; w++) { v[w] = plaintext[w]; } for (size_t n = 0; n < nrounds; n += 8) { for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 0) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 3) % 8], perm[3]); for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 4) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 7) % 8], perm[3]); } for (size_t w = 0; w < nwords; w++) { ciphertext[w] = v[w] + xkey[w]; } } void decrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], string key) { u64 xkey[nwords] = {0}; string_to_u64_array(nwords, key, xkey); size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 v[nwords] = {0}; for (size_t w = 0; w < nwords; w++) { v[w] = ciphertext[w] - xkey[w]; } for (int n = nrounds - 8; n >= 0; n -= 8) { threefish_roundinv(nwords, v, rot[(n + 7) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 4) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } threefish_roundinv(nwords, v, rot[(n + 3) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 0) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } } for (size_t w = 0; w < nwords; w++) { plaintext[w] = v[w]; } } void encrypt_string(string s, u64 ciphertext[]) { string p = "halloooo"; size_t min_array_size = get_min_array_size(s.size()); u64 plaintext[min_array_size] = {0}; string_to_u64_array(min_array_size, s, plaintext); encrypt(min_array_size, plaintext, ciphertext, p); } string decrypt_string(size_t min_array_size, u64 ciphertext[]) { string p = "halloooo"; u64 plaintext[min_array_size] = {0}; decrypt(min_array_size, plaintext, ciphertext, p); return u64_array_to_string(min_array_size, plaintext); } int main() { string s1 = "moinnnnn"; size_t min_array_size = get_min_array_size(s1.size()); u64 ciphertext[min_array_size] = {0}; cout << s1 << endl; encrypt_string(s1, ciphertext); string s2 = decrypt_string(min_array_size, ciphertext); cout << s2 << endl; return 0; }
Irgendetwas sehe ich dabei nicht - kann mir das nicht erklärn.
-
Schon mal etwas von Debugging gehört?
-
@Th69 sagte in Threefish selber implementieren:
Schon mal etwas von Debugging gehört?
Dauert zu lange da mit dem Debugger durchzugehen. Hast du auch einen konstruktiven Vorschlag?
-
@EinNutzer0 ernsthaft? Du erwartest, dass wir uns mit deinem Code beschäftigen, machst das aber selbst nicht... Ich bin gerne hilfsbereit, aber jetzt bin ich raus.
Wenn mit dem Debugger durchgehen zu lange dauert, lern ihn zu benutzen.
-
@EinNutzer0 sagte in Threefish selber implementieren:
Dauert zu lange da mit dem Debugger durchzugehen.
-
Der Code compiliert mit clang nicht einmal.
einnutzer0.cpp:95:14: error: variable-sized object may not be initialized u64 xkey[nwords] = {0}; ^~~~~~ einnutzer0.cpp:116:11: error: variable-sized object may not be initialized u64 v[nwords] = {0}; ^~~~~~ einnutzer0.cpp:149:14: error: variable-sized object may not be initialized u64 xkey[nwords] = {0}; ^~~~~~ einnutzer0.cpp:170:11: error: variable-sized object may not be initialized u64 v[nwords] = {0}; ^~~~~~ einnutzer0.cpp:206:19: error: variable-sized object may not be initialized u64 plaintext[min_array_size] = {0}; ^~~~~~~~~~~~~~ einnutzer0.cpp:214:19: error: variable-sized object may not be initialized u64 plaintext[min_array_size] = {0}; ^~~~~~~~~~~~~~ einnutzer0.cpp:223:20: error: variable-sized object may not be initialized u64 ciphertext[min_array_size] = {0}; ^~~~~~~~~~~~~~
-
Habs, wenn beide Länge 8 haben, funktioniert es schon mal...
#include <cstdint> #include <cstring> #include <iostream> #include <sstream> using namespace std; typedef uint8_t u8; typedef uint64_t u64; size_t min_len_from_string(size_t len) { while (len <= 72 * 8 || len % 8 != 0) { len++; } return len / 8; } size_t min_len_from_string_2(size_t len) { return len / 8; } void string_to_u64_array(size_t min_array_size, string s1, u64 a[]) { string s2 = ""; for (size_t i = 0; i < min_array_size * 8; i++) { s2 += s1[i % s1.length()]; } for (size_t i = 0; i < min_array_size; i++) { a[i] = 0; for (size_t j = 0; j < 8; j++) { a[i] <<= 8; a[i] |= (u8)s2[i * 8 + j]; } } } string u64_array_to_string(size_t min_array_size, u64 a[]) { string s = ""; for (size_t i = 0; i < min_array_size; i++) { u64 t = a[i]; for (size_t j = 0; j < 8; j++) { u8 c = (u8)t; s.insert(0,1,c); t >>= 8; } } return s; } u64 rl64(u64 x, u8 r) { return (x << (r & 63)) | (x >> (64 - (r & 63))); } u64 rr64(u64 x, u8 r) { return (x >> (r & 63)) | (x << (64 - (r & 63))); } void mix(u64 a, u64 b, u64 *c, u64 *d, u8 r) { u64 tmp = a + b; *d = rl64(b, r) ^ tmp; *c = tmp; } void mixinv(u64 c, u64 d, u64 *a, u64 *b, u8 r) { u64 tmp = rr64(c ^ d, r); *a = c - tmp; *b = tmp; } void threefish_round(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mix(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void threefish_roundinv(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mixinv(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void encrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], string key) { u64 xkey[nwords] = {0}; string_to_u64_array(nwords, key, xkey); size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 v[nwords] = {0}; for (size_t w = 0; w < nwords; w++) { v[w] = plaintext[w]; } for (size_t n = 0; n < nrounds; n += 8) { for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 0) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 3) % 8], perm[3]); for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 4) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 7) % 8], perm[3]); } for (size_t w = 0; w < nwords; w++) { ciphertext[w] = v[w] + xkey[w]; } } void decrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], string key) { u64 xkey[nwords] = {0}; string_to_u64_array(nwords, key, xkey); size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64 v[nwords] = {0}; for (size_t w = 0; w < nwords; w++) { v[w] = ciphertext[w] - xkey[w]; } for (int n = nrounds - 8; n >= 0; n -= 8) { threefish_roundinv(nwords, v, rot[(n + 7) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 4) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } threefish_roundinv(nwords, v, rot[(n + 3) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 0) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } } for (size_t w = 0; w < nwords; w++) { plaintext[w] = v[w]; } } void encrypt_string(size_t len, size_t min_array_size, size_t min_string_size , string s, u64 ciphertext[]) { string p = "Buchstab"; u64 plaintext[min_array_size] = {0}; string_to_u64_array(len, s, plaintext); encrypt(len, plaintext, ciphertext, p); } string decrypt_string(size_t len, size_t min_array_size, size_t min_string_size , u64 ciphertext[]) { string p = "Buchstab"; u64 plaintext[min_array_size] = {0}; decrypt(len, plaintext, ciphertext, p); return u64_array_to_string(min_string_size, plaintext); } int main() { string s1 = "HhaLLoio"; size_t len = s1.length(); size_t min_array_size = min_len_from_string(len); size_t min_string_size = min_len_from_string_2(len); u64 ciphertext[min_array_size] = {0}; cout << s1 << endl; encrypt_string(len, min_array_size, min_string_size, s1, ciphertext); string s2 = decrypt_string(len, min_array_size, min_string_size, ciphertext); cout << s2 << endl; return 0; }
Das Problem war, die string Länge war zu klein, und das Ergebnis wurde umgekehrt herum zusammengesetzt...
-
@EinNutzer0 sagte in Threefish selber implementieren:
Dauert zu lange da mit dem Debugger durchzugehen. Hast du auch einen konstruktiven Vorschlag?
Dann hast du einen zentralen Punkt der Software-Entwicklung nicht verstanden.
Lern Lesen! Oder warum glaubst du dass ein Testvektor mit Nullen beginnt? Siehe auch letzten Beitrag von mir.
Fehlerreduktion erreiche ich nicht durch scharfes Ansehen des Codes (Stichwort Fehlerblindheit) sondern durch:
- Testreihen / Unittests -> Liefert der Code das richtige Ergebnis?
- Assertions -> Sind meine Annahmen korrekt?
- Debuggen -> Was geht im Code ab?
PS:
Ich koche ja auch nicht ohne abzuschmecken.
-
@EinNutzer0 sagte in Threefish selber implementieren:
@Th69 sagte in Threefish selber implementieren:
Schon mal etwas von Debugging gehört?
Dauert zu lange da mit dem Debugger durchzugehen. Hast du auch einen konstruktiven Vorschlag?
Die Anforderung an ein Minimalbeispiel hier im Forum kommt nicht von ungefähr. Auch im täglichen Business ist es sinnvoll das Problem soweit zu reduzieren, bzw. zu extrahieren, bis es überschaubar ist. Bei deinem Mini-Quellcode ist das noch recht einfach. Nutze die Zeit und lerne Debuggen. Als Entwickler sollte man seinen Debugger mindestens so gut kennen, wie den Rest der IDE.
- Abgesehen davon: "Lerne Debuggen" ist ein konstruktiver Vorschlag.
- Du bist noch lange nicht so gut, dass du es dir erlauben kannst, den alten Hasen vorzuwerfen, sie wären nicht konstruktiv.
-
Mal etwas anderes:
https://i.postimg.cc/hjdsGS38/grafik.png
Was muss ich hier umstellen, damit mich Visual Studio nicht anmeckert, dass nur Arrays mit konstanten Werten erstellt werden dürfen? Ich vermute, das ist nicht ISO-Standard...
Na ja, und zurück zum ursprünglichen Problem... Ich glaube, dass es sinnvoller ist, alles neu zu schreiben, anstatt mit dem Debugger (mehrere) Nadeln im Heuhaufen zu suchen...
... um etwas dabei zu lernen, auf jeden Fall.
-
Gar nicht, denn das gibt es in C++ schlichtweg nicht, weil wofür? Selbst in C wurden die wieder abgeschafft. Und wenn du altes C machen würdest, dann sind die auch anders gedacht als du denkst, aber das ist erst einmal egal, weil du ja kein altes C machst.
-
@EinNutzer0 sagte in Threefish selber implementieren:
Was muss ich hier umstellen, damit mich Visual Studio nicht anmeckert, dass nur Arrays mit konstanten Werten erstellt werden dürfen? Ich vermute, das ist nicht ISO-Standard...
Microsoft hatte nie einen compliant C-Compiler. Leb' Damit. Auch: Wer VLAs braucht hat die Kontrolle über sein Leben verloren.
-
Bin mit dem Debugger durch:
// ConsoleApplication1.cpp : Diese Datei enthält die Funktion "main". Hier beginnt und endet die Ausführung des Programms. // #include <cstdint> #include <cstring> #include <iostream> #include <sstream> using namespace std; typedef uint8_t u8; typedef uint64_t u64; struct sizes { const size_t len1, len2, len3; }; sizes get_sizes(const string& s) { size_t len1 = s.length(); size_t len2 = 72 * 8; if (len2 < len1) { len2 = len1; } while (len2 % 8 != 0) { len2++; } size_t len3 = len2 * 8; sizes ss{ len1, len2, len3 }; return ss; } size_t min_len_from_string(size_t len) { while (len <= 72 * 8 || len % 8 != 0) { len++; } return len / 8; } size_t min_len_from_string_2(size_t len) { return len / 8; } void string_to_u64_array(const size_t len, const string& s1, u64 a[]) { string s2 = ""; for (size_t i = 0; i < len * 8; i++) { s2 += s1[i % s1.length()]; } for (size_t i = 0; i < len; i++) { a[i] = 0; for (size_t j = 0; j < 8; j++) { a[i] <<= 8; a[i] |= (u8)s2[i * 8 + j]; } } } string u64_array_to_string(const size_t len, u64 a[]) { string s = ""; for (size_t i = 0; i < len; i++) { u64 t = a[i]; for (size_t j = 0; j < 8; j++) { u8 c = (u8)t; s.insert(0, 1, c); t >>= 8; } } return s; } u64 rl64(u64 x, u8 r) { return (x << (r & 63)) | (x >> (64 - (r & 63))); } u64 rr64(u64 x, u8 r) { return (x >> (r & 63)) | (x << (64 - (r & 63))); } void mix(u64 a, u64 b, u64* c, u64* d, u8 r) { u64 tmp = a + b; *d = rl64(b, r) ^ tmp; *c = tmp; } void mixinv(u64 c, u64 d, u64* a, u64* b, u8 r) { u64 tmp = rr64(c ^ d, r); *a = c - tmp; *b = tmp; } void threefish_round(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mix(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void threefish_roundinv(size_t nwords, u64 v[], u8 r[], u8 p[]) { for (size_t w = 0; w < nwords; w += 2) { mixinv(v[p[w]], v[p[w + 1]], &v[p[w]], &v[p[w + 1]], r[w / 2]); } } void encrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], u64 xkey[]) { size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64* v = new u64[nwords]; for (size_t w = 0; w < nwords; w++) { v[w] = plaintext[w]; } for (size_t n = 0; n < nrounds; n += 8) { for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 0) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 3) % 8], perm[3]); for (size_t w = 0; w < nwords; w++) { v[w] += xkey[w]; } threefish_round(nwords, v, rot[(n + 4) % 8], perm[0]); threefish_round(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_round(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_round(nwords, v, rot[(n + 7) % 8], perm[3]); } for (size_t w = 0; w < nwords; w++) { ciphertext[w] = v[w] + xkey[w]; } delete[] v; } void decrypt(size_t nwords, u64 plaintext[], u64 ciphertext[], u64 xkey[]) { size_t nrounds = 72; u8 rot[8][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, }; u8 perm[4][4] = { {0, 1, 2, 3}, {0, 3, 2, 1}, {0, 1, 2, 3}, {0, 3, 2, 1}, }; u64* v = new u64[nwords]; for (size_t w = 0; w < nwords; w++) { v[w] = ciphertext[w] - xkey[w]; } for (int n = (int)nrounds - 8; n >= 0; n -= 8) { threefish_roundinv(nwords, v, rot[(n + 7) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 6) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 5) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 4) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } threefish_roundinv(nwords, v, rot[(n + 3) % 8], perm[3]); threefish_roundinv(nwords, v, rot[(n + 2) % 8], perm[2]); threefish_roundinv(nwords, v, rot[(n + 1) % 8], perm[1]); threefish_roundinv(nwords, v, rot[(n + 0) % 8], perm[0]); for (size_t w = 0; w < nwords; w++) { v[w] -= xkey[w]; } } for (size_t w = 0; w < nwords; w++) { plaintext[w] = v[w]; } delete[] v; } string encrypt_string_with_password(const sizes ss, const string& s, const string& p) { u64* plaintext = new u64[ss.len2]; u64* ciphertext = new u64[ss.len2]; u64* xkey = new u64[ss.len2]; string_to_u64_array(ss.len2, s, plaintext); string_to_u64_array(ss.len2, p, xkey); encrypt(ss.len2, plaintext, ciphertext, xkey); string r = u64_array_to_string(ss.len2, ciphertext); delete[] plaintext, ciphertext, xkey; return r; } string decrypt_string_with_password(const sizes ss, const string& s, const string& p) { u64* plaintext = new u64[ss.len3]; u64* ciphertext = new u64[ss.len3]; u64* xkey = new u64[ss.len3]; string_to_u64_array(ss.len3, s, ciphertext); string_to_u64_array(ss.len3, p, xkey); decrypt(ss.len3, plaintext, ciphertext, xkey); string r = u64_array_to_string(ss.len1, plaintext); delete[] plaintext, ciphertext, xkey; return r; } int main() { string s = "HhaLLoio"; string p = "Buchstab"; sizes ss = get_sizes(s); string e = encrypt_string_with_password(ss, s, p); string d = decrypt_string_with_password(ss, e, p); cout << e << endl; return 0; } // Programm ausführen: STRG+F5 oder Menüeintrag "Debuggen" > "Starten ohne Debuggen starten" // Programm debuggen: F5 oder "Debuggen" > Menü "Debuggen starten" // Tipps für den Einstieg: // 1. Verwenden Sie das Projektmappen-Explorer-Fenster zum Hinzufügen/Verwalten von Dateien. // 2. Verwenden Sie das Team Explorer-Fenster zum Herstellen einer Verbindung mit der Quellcodeverwaltung. // 3. Verwenden Sie das Ausgabefenster, um die Buildausgabe und andere Nachrichten anzuzeigen. // 4. Verwenden Sie das Fenster "Fehlerliste", um Fehler anzuzeigen. // 5. Wechseln Sie zu "Projekt" > "Neues Element hinzufügen", um neue Codedateien zu erstellen, bzw. zu "Projekt" > "Vorhandenes Element hinzufügen", um dem Projekt vorhandene Codedateien hinzuzufügen. // 6. Um dieses Projekt später erneut zu öffnen, wechseln Sie zu "Datei" > "Öffnen" > "Projekt", und wählen Sie die SLN-Datei aus.
Zeile 201: C6385: Ungültige Daten werden aus "rot" gelesen.
Und genau das verstehe ich nicht, kann mir jemand helfen?
Die Speicherzugriffsverletzung erfolgt wohl in Zeile 117:
r[w / 2]);
.