前にC++でchachaを実装したのですが、stateを16進数に変換してkey streamにするときにミスをしていたので、key streamのbyte数がおかしいことになっていました。それに今頃気がついたので、修正しました。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <array> | |
#include <cstring> | |
#include <vector> | |
#include <fstream> | |
#include <sstream> | |
using namespace std; | |
//出典:https://boringssl.googlesource.com/boringssl/+/master/crypto/chacha/chacha.c | |
#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) | |
#define QR(a, b, c, d) ( \ | |
a += b, d ^= a, d = ROTL(d,16), \ | |
c += d, b ^= c, b = ROTL(b,12), \ | |
a += b, d ^= a, d = ROTL(d, 8), \ | |
c += d, b ^= c, b = ROTL(b, 7)) | |
#define ROUNDS 20 | |
uint32_t plus32(uint32_t x,uint32_t y){ | |
return (x+y) & 0xffffffff; | |
} | |
array<uint32_t,32> make_array_key(string s){ | |
array<uint32_t,32> key; | |
int count = 0; | |
for(int i=0;i < s.size();i+=2){ | |
string tmp; | |
tmp += s[i]; | |
tmp += s[i+1]; | |
key[count] = stoi(tmp, nullptr, 16); | |
count++; | |
tmp.clear(); | |
} | |
return key; | |
} | |
array<uint32_t,8> make_array_nonce(string s){ | |
array<uint32_t,8> key; | |
int count = 0; | |
for(int i=0;i < s.size();i+=2){ | |
string tmp; | |
tmp += s[i]; | |
tmp += s[i+1]; | |
key[count] = stoi(tmp, nullptr, 16); | |
count++; | |
tmp.clear(); | |
} | |
return key; | |
} | |
string key_generate(int a, int b, int c, int d){ | |
string sub_key; | |
int bc[4] = {a, b, c, d}; | |
for(int i = 0; i < 4; i++){ | |
char c; | |
if(bc[i] < 10){ | |
c = bc[i] + '0'; | |
}else{ | |
if(bc[i] == 10) c = 'a'; | |
if(bc[i] == 11) c = 'b'; | |
if(bc[i] == 12) c = 'b'; | |
if(bc[i] == 13) c = 'd'; | |
if(bc[i] == 14) c = 'e'; | |
if(bc[i] == 15) c = 'f'; | |
} | |
sub_key.push_back(c); | |
} | |
return sub_key; | |
} | |
string chacha(string key, string nonce) { | |
//Initial Stateを作成する。 | |
array<uint32_t,64> in = {101, 120, 112, 97, | |
110, 100, 32 , 51, | |
50, 45, 98 , 121, | |
116, 101, 32, 107}; | |
//↑はconstを2進数にしたものをInital Stateに代入している | |
//次の3つはkey,block_count,nonceの配列を作成している。 | |
array<uint32_t,32> k(make_array_key(key)); | |
array<uint32_t, 8> block_count = {0, 0, 0, 0, 0, 0, 0, 0}; | |
array<uint32_t, 8> n(make_array_nonce(nonce)); | |
for(int i = 16; i < 64; i++){ | |
if(i >= 16 && i < 48){ | |
in[i] = k[i - 16]; | |
}else if(i >= 48 && i < 56){ | |
in[i] = block_count[i - 48]; | |
}else{ | |
in[i] = n[i - 56]; | |
} | |
} | |
/*4*4のInital Stateに変換する。64要素あるInital Stateを4要素ずつ取り出し、リトルエンディアンに変換して4*4行列に代入する。 | |
この時、4*4行列ではなく、QRの計算のために1*16行列にする。つまり、このあと計算するのはIn[]ではなく、x[]である。 | |
また、これはリトルエンディアンにしている。*/ | |
uint32_t x[16]={}; | |
for(int i = 0; i < 64; i+=4){ | |
x[i / 4] = in[i] | (in[i+1] << 8) | (in[i+2] << 16) | (in[i+3] << 24); | |
} | |
//QR前のx[]をコピーする。 | |
uint32_t cp[16]={}; | |
for(int i = 0; i < 16; i++){ | |
cp[i] = x[i]; | |
} | |
//x[]をQRに通す | |
for(int i = 0; i < ROUNDS; i += 2){ | |
// Odd round | |
QR(x[0], x[4], x[ 8], x[12]); // column 0 | |
QR(x[1], x[5], x[ 9], x[13]); // column 1 | |
QR(x[2], x[6], x[10], x[14]); // column 2 | |
QR(x[3], x[7], x[11], x[15]); // column 3 | |
// Even round | |
QR(x[0], x[5], x[10], x[15]); // diagonal 1 (main diagonal) | |
QR(x[1], x[6], x[11], x[12]); // diagonal 2 | |
QR(x[2], x[7], x[ 8], x[13]); // diagonal 3 | |
QR(x[3], x[4], x[ 9], x[14]); // diagonal 4 | |
} | |
//QR前x[]とQR後x[]を2^32を法とする加算を行う。 | |
for(int i = 0; i < 16; i++){ | |
x[i] = plus32(x[i], cp[i]); | |
} | |
//リトルエンディアンを逆変換する | |
uint32_t result[64]={}; | |
for(int i = 0; i < 64; i +=4){ | |
result[i] = (x[i/4] & 0xff); | |
result[i+1] = ((x[i/4] >> 8) & 0xff); | |
result[i+2] = ((x[i/4] >> 16) & 0xff); | |
result[i+3] = ((x[i/4] >> 24) & 0xff); | |
} | |
//16進数のstring型に変換する。これがkey_steam。 | |
string key_stream; | |
for(int i = 0; i < 64; i++){ | |
stringstream ss; | |
ss << hex << result[i]; | |
if(ss.str().size() != 2 ){ | |
string s = '0'+ss.str(); | |
key_stream += s; | |
}else{ | |
key_stream += ss.str(); | |
} | |
} | |
return key_stream; | |
} | |
int main(int argc, char const *argv[]) { | |
string key="0000000000000000000000000000000000000000000000000000000000000000", nonce="0000000000000000"; | |
string key_stream; | |
long long int count = 1; | |
vector<string> mini_key; | |
bool flag = 0; //mini_key作成のループ抜ける用 | |
//4wordsのmini_keyを作成。これを16個あつめてkeyを作る(予定) | |
while(1){ | |
for(int i = 0; i < 16; i++){ | |
for(int j = 0; j < 16; j++){ | |
for(int k = 0; k < 16; k++){ | |
for(int l = 0; l < 16; l++){ | |
// cout<<"i,j,k,l="<<i<<","<<j<<","<<k<<","<<l<<","<<"mini_key="<<key_generate(i , j , k ,l)<<endl; | |
mini_key.push_back(key_generate(i , j , k ,l)) ; | |
if(i == 15 && j == 15 && k == 15 && l == 15) flag = 1; | |
} | |
} | |
} | |
} | |
if(flag == 1) break; | |
} | |
cout<<"Writing...Please wait..."<<endl; //実行中何も表示されないと寂しいので | |
//keytを作成して、chacha関数からkey_streamを受け取り、ファイルに出力する。 | |
for(int i = 0;i < 65536; i++){ | |
for(int j = 0; j < 4; j++){ | |
key[j] = mini_key[i][j]; | |
} | |
key_stream = chacha(key, nonce); | |
//ファイル出力 | |
string filename = "key_stream_result.txt"; | |
ofstream writing_file; | |
writing_file.open(filename, ios::app); | |
writing_file << key_stream << endl; | |
writing_file << "key size="<<key_stream.size()<<endl; | |
if(count % 1000 == 0) cout<<"Now,count is"<<count<<endl; //暇つぶし | |
count++; | |
} | |
cout<<dec<<count<<endl; | |
return 0; | |
} |
ミスっていた点は、144行目~150行目です。ここは追加した点ではあるのですが。
何をミスっていたかといえば、10進数を16進数char型に変換するところで0埋めしないので、例えば0bとなるところをbとしか出力しませんでした。
そういうわけで、0埋めするようにしました。これでkey streamがしっかり128文字になるようになりました。
いい加減keyとnonceのコードをなにかするので、はい。流石に正月三が日が終わるまでには・・・。
しかし、ぶっちゃけ、planetext recoveryできない気がしてきたので、マジでやばいです。偏りない気がする。