ttki's diary

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

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

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

まずハッシュ関数とは、主に暗号化通信(通信販売など amazon 楽天...etc)に使われています。
例えば、クライアントがサーバーにパスワードを送るとします。
その時、生のままのパスワードをサーバーに送っては危険ですね...
そんなとき、ハッシュ関数(有名なものに MD5 SHA などがある MD5 は Mac 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 のオブジェクトに () をつけて関数形式にすると、ハッシュ化した文字列を返します。
*/

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

## 余談

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