ttki's diary

プログラミング好きな人の日記です

ハッシュ関数をつくってみた (完成形

今回は、この前の適当なハッシュ関数の説明をします。

まずハッシュ関数とは、主に暗号化通信(通信販売など amazon 楽天...etc)に使われています。
例えば、クライアントがサーバーにパスワードを送るとします。
その時、生のままのパスワードをサーバーに送っては危険ですね...
そんなとき、ハッシュ関数(有名なものに MD5 SHA などがある MD5Mac Linux などで MD5コマンドを使うことができるので知っている方も多いと思う) を使います。
ハッシュ関数は主に、文字列などから特定のビット数(128, 160, 256...) のハッシュ値を計算します。
ハッシュ関数には、
   ・ハッシュ値から、元の数値を計算できない。
   ・同じハッシュ値を持つ文字列などを2つ以上生成することがとても難しい。
などの特性があります。

このことから、ハッシュ関数を使うと
・クライアントはユーザーのパスワードのハッシュ値を計算。
   ・サーバーは送られてきたハッシュ値とサーバー内のハッシュ値とを比較。
することで、安全にユーザー認証できるというわけです。
それに、サーバー内に生のパスワードがあったら危険ですからね。

というわけで、このようなハッシュ関数を作ってみました。
最初は、SHA-1 を実装してみようと思ったのですが、いい情報がなかったので自分で作りました。
かーなり、安全性に欠けているかも知れませんが、ファイル比較程度には使えるはずです。

なにかあったら、コメントお願いします^^

コード

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int BIT = 8;
const int prime[9] = { 11, 13, 17, 19, 23, 29, 31, 37};
const int NUM = 16777931;

class HD
{
public:
	HD();
	char digest[33];
	int hash(char [], int, unsigned int[]);
	int shash(char []);
	void clear();
	void operator = (char *ch);
	char* operator ()();
};

HD::HD()
{
	memset(digest, 0, 33);
}

void HD::operator = (char *ch)
{
	shash(ch);
}

char* HD::operator ()()
{
	return digest;
}

void HD::clear()
{
	memset(digest, 0, 33);
}

int HD::hash(char word1[],int wordsz1, unsigned int data[])
{
	unsigned int i=0, j=0, k = 2166136261, l = 0, data2[BIT] = {0};
	char word[32] = { 0 };
	unsigned long A, B, C, D, E, F, G, H;// Hash Register

	memset(data,0,BIT);

	for(l = 0; l < 2; l++)
	{
		k = (k * NUM) ^ word[i % 32];
		for(i = 0; i < BIT; i++)
		{
			word[i % 32] |= k << 2;
			word[i % 32] += word1[i];
			word[i % 32] ^= word1[i] * k;
		}
	}

	for(i = 0; word1[i] != 0; i++)
	{
		k = (k * NUM) + word1[i]  + word[i % 32];
		data[i % BIT] *= word[i % 32];
		data[i % BIT] += k;
	}

	for(i = 0; i < BIT; i++)
	{
		k = (k * NUM) + data[i];
		data[i] ^= prime[i] * k;
		data[i] &= prime[i] + k;
		data[i] += prime[i];
		data[i] += (data[i] & k) ^ ~k;
	}

	data2[0] = data[0];		A = data2[7];
	data2[1] = data[1];		B = data2[0];
	data2[2] = data[2];		C = data2[1];
	data2[3] = data[3];		D = data2[2];
	data2[4] = data[4];		E = data2[3];
	data2[5] = data[5];		F = data2[4];
	data2[6] = data[6];		G = data2[5];
	data2[7] = data[7];		H = data2[6];

	memset(data, 0, BIT);

	for(j = 0; j < 64; j++)
	{
		k = (k * NUM) + A + B + C + D + E + F + G + H;

		A = (A = A ^ H * ~k) * (A = A ^ (k * A) ^ ~H);
		B = (B = B ^ G * ~k) * (B = B ^ (k * B) ^ ~G);
		C = (C = C ^ F * ~k) * (C = C ^ (k * C) ^ ~F);
		D = (D = D ^ E * ~k) * (D = D ^ (k * D) ^ ~E);
		E = (E = E ^ D * ~k) * (E = E ^ (k * E) ^ ~D);
		F = (F = F ^ C * ~k) * (F = F ^ (k * F) ^ ~C);
		G = (G = G ^ B * ~k) * (G = G ^ (k * G) ^ ~B);
		H = (H = H ^ A * ~k) * (H = H ^ (k * H) ^ ~A);

		A = ((H = A ^ (A * (A % k))) | (k * A)) ^ (k + H) ^ (~A);
		B = ((G = B ^ (B * (B % k))) | (k * B)) ^ (k + G) ^ (~B);
		C = ((F = C ^ (C * (C % k))) | (k * C)) ^ (k + F) ^ (~C);
		D = ((E = D ^ (D * (D % k))) | (k * D)) ^ (k + E) ^ (~D);
		E = ((D = E ^ (E * (E % k))) | (k * E)) ^ (k + D) ^ (~E);
		F = ((C = F ^ (F * (F % k))) | (k * F)) ^ (k + C) ^ (~F);
		G = ((B = G ^ (G * (G % k))) | (k * G)) ^ (k + B) ^ (~G);
		H = ((A = H ^ (H * (H % k))) | (k * H)) ^ (k + A) ^ (~H);

		A ^= (A | ~A); A += (B | ~H);
		B ^= (B | ~B); B += (C | ~G);
		C ^= (C | ~C); C += (D | ~F);
		D ^= (D | ~D); D += (E | ~E);
		E ^= (E | ~E); E += (F | ~D);
		F ^= (F | ~F); F += (G | ~C);
		G ^= (G | ~G); G += (H | ~B);
		H ^= (H | ~H); H += (A | ~A);

		data2[0] = A;	A = data2[7];
		data2[1] = B;	B = data2[0];
		data2[2] = C;	C = data2[1];
		data2[3] = D;	D = data2[2];
		data2[4] = E;	E = data2[3];
		data2[5] = F;	F = data2[4];
		data2[6] = G;	G = data2[5];
		data2[7] = H;	H = data2[6];

	}

	{// Copy
		data[0] = A;
		data[1] = B;
		data[2] = C;
		data[3] = D;
		data[4] = E;
		data[5] = F;
		data[6] = G;
		data[7] = H;
	}

	for(i = 0; i < BIT; i++)
	{
		data[i] %= 65535;
		if(data[i] < 0) data[i] = -data[i];
	}

	return 0;
}

int HD::shash(char word[])
{
	unsigned int data[BIT] = { 0 },i = 0, wordsz = 0;
	wordsz = strlen(word);
	memset(digest, 0, 33);
	hash(word,wordsz,data);
	for(i = 0; i < BIT; i++)
	{
		sprintf(digest, "%s%04x", digest, data[i]);
	}
	return 0;
}


int main()
{
	char str[512] = { 0 };
	HD hash;// 自作のハッシュ関数

	hash = str;// 文字列を HD object に代入

	cout << str << " : " << hash()// Hash 後の文字列 32文字 + \0
	 		 << endl;

	strcpy(str, "The quick brown fox jumps lazy dog");
	hash = str;

	cout << (char *)str << " : " << hash() << endl;

	strcpy(str, "The quick brown fox jumps lazy cog");
	hash = str;

	cout << (char *)str << " : " << hash() << endl;

	return 0;
}
/* HD ハッシュ関数のクラス
   HD のオブジェクトに文字列を代入するとハッシュ化します (operator =)
   HD のオブジェクトに () をつけて関数形式にすると、ハッシュ化した文字列を返します。
*/

ちょっと見にくいですね...

## 余談

最近 GCCGitHub Atom Editor をインストールしました。
GCC 持ってなかったの?? と突っ込まれそうですが Visual C++ 2010 を使っていたので持っていなかったんです...
やっぱ持っているといいですね^^ Atom editor も GitHub が作ったと聞いてダウンロードしてみました。
ちょっと、重いかもしれませんが、色々設定すれば短形選択できたりデフォルトで C/C++シンタックスカラーリングをサポートしていたりととてもよいものでした。
とりあえず USB Memory にいれて、環境の整っていない PC などでコンパイルできるようになりました!!
うれしい!!