#include "StdAfx.h"
#include "AuthenticateManager.h"
#include "TextTools.h"
#include "Base64.h"
#include "CryptTools.h"
#include "DigestAuthenticate.h"

#define	PRIVATE_KEY_LENGTH	8
#define	TIME_LENGTH			16
#define	NONCE_MIN_LENGTH	(PRIVATE_KEY_LENGTH + 1 + TIME_LENGTH + 1)

CAuthenticateManager::CAuthenticateManager(void)
{
}

CAuthenticateManager::~CAuthenticateManager(void)
{
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//	インタフェース
/////////////////////////////////////////////////////////////////////////////////////////////////////
/*!
	開始
*/
void CAuthenticateManager::Start(CWorkspaceAccess setting)
{
	m_setting = setting;

	//	スクランブルキーを設定
	srand((unsigned int)CTime::GetCurrentTime().GetTime() + GetTickCount());
	m_scrambleKey.AppendDoubleWord(rand());
	m_scrambleKey.AppendDoubleWord(rand());
	m_scrambleKey.AppendDoubleWord(rand());
	m_scrambleKey.AppendDoubleWord(rand());

	//	プライベートキー取得
	for(int i=0;i<PRIVATE_KEY_LENGTH;i++)
		m_privateKey += (TCHAR)((rand() % 27) + _T('a'));

	//	Nonce利用可能期間
	m_expireTime = setting.GetKeyInt(_T("Authenticate::NonceLifeTime"), 60) * 60;	//	60分間
/*

	CWorkspace	test;
	CDigestAuthenticate::ParseAuthOptionLine("Digest username=\"\", realm=\"Secret, Zone,\", nonce=\"RMH1usDrAwA=6dc290ea3304de42a7347e0a94089ff5912ce0de\", uri=\"/~68user/net/sample/http-auth-digest/secret.html\", algorithm=MD5, qop=auth, nc=00000001,  cnonce=\"e79e26e0d17c978d\", response=\"0d73182c1602ce8749feeb4b89389019\"", test.GetAccess(""));
//CheckNonce(CreateNonce());
*/
}


/*!
	ユーザのパスワードを確認

	\return FALSE:認証不可, TRUE:認証OK
*/
int CAuthenticateManager::GetUserPasswd(CString userName, CString &passwd)
{
	CWorkspaceAccess	enableUser = m_setting.GetAccess("User::Enable");

	//	有効なユーザを検索
	CStringArray	userList;
	enableUser.GetAllSubNode(userList);
	for(int i=0;i<userList.GetSize();i++)
	{
		CWorkspaceAccess user = enableUser.GetAccess(userList[i]);
		if(user.GetConfig(_T("User"), _T("")) == userName)
		{
			passwd = user.GetConfig(_T("Passwd"), _T(""));
			return(TRUE);
		}
	}
	return(FALSE);
}

/*!
	nonce生成
*/
CString CAuthenticateManager::CreateNonce(CString tag)
{
	//	平文準備
	CString	src = CTextTools::GetFormat(_T("%016I64x:%s:%s"), CTime::GetCurrentTime().GetTime(), m_privateKey, tag);
	CBinaryData	bSrc;
	bSrc.AppendString(src);

	//	RC4
	CBinaryData	crypted;
	CCryptTools::CryptRC4(bSrc, crypted, m_scrambleKey);

	//	B64
	CString	b64;
	CBase64::Encode64bin(crypted, b64);

	return(b64);
}

/*!
	nonceチェック

	\return FALSE:認証不可, TRUE:認証OK
*/
int CAuthenticateManager::CheckNonce(CString nonce, CString tag)
{
	//	B64
	CString		b64;
	CBinaryData	crypted;
	CBase64::Decode64bin(nonce, crypted);

	//	暗号化準備
	CBinaryData	bSrc;
	CCryptTools::CryptRC4(crypted, bSrc, m_scrambleKey);

	//	長さチェック
	CString	src = bSrc.GetString();
	if(src.GetLength() < NONCE_MIN_LENGTH)
		return FALSE;

	//	キー取得
	CString	privateKey = src.Mid(TIME_LENGTH + 1, PRIVATE_KEY_LENGTH);
	if(privateKey != m_privateKey)
		return FALSE;

	//	タグ取得
	CString	tagRet = src.Mid(NONCE_MIN_LENGTH);
	if(tagRet != tag)
		return FALSE;

	//	時刻取得
	CString	strTime = src.Mid(0, TIME_LENGTH);
	__time64_t	time = _strtoi64(strTime, NULL, 16);
	if(time == 0)
		return FALSE;

	//	時間経過をチェック
	if(CTime(time) + m_expireTime < CTime::GetCurrentTime())
		return FALSE;

	return TRUE;
}

