128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/* $Id$ */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/** @file
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Main - Password Hashing
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/*
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Copyright (C) 2012 Oracle Corporation
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * available from http://www.virtualbox.org. This file is free software;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * General Public License (GPL) as published by the Free Software
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/*******************************************************************************
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync* Header Files *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync*******************************************************************************/
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync#include "HashedPw.h"
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync#include <iprt/assert.h>
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync#include <iprt/ctype.h>
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync#include <iprt/sha.h>
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync#include <iprt/string.h>
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/*******************************************************************************
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync* Global Variables *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync*******************************************************************************/
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/**
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * The prefix of a hashed password.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsyncstatic const char s_szHashedPwPrefix[] = "#SHA-512#";
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/**
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Checks if the password is a hashed one or not.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Empty password are not considered hashed.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * @returns true if hashed, false if not.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * @param a_pstrPassword Password to inspect.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsyncbool VBoxIsPasswordHashed(RTCString const *a_pstrPassword)
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync{
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* prefix */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync if (!a_pstrPassword->startsWith(s_szHashedPwPrefix))
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync return false;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* salt (optional) */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync const char *pszSalt = a_pstrPassword->c_str() + sizeof(s_szHashedPwPrefix) - 1;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync const char *pszSaltEnd = strchr(pszSalt, '#');
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync if (!pszSaltEnd)
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync return false;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync while (pszSalt != pszSaltEnd)
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync {
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync if (!RT_C_IS_XDIGIT(*pszSalt))
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync return false;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync pszSalt++;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync }
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* hash */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync uint8_t abHash[RTSHA512_HASH_SIZE];
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync int rc = RTSha512FromString(pszSaltEnd + 1, abHash);
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync return RT_SUCCESS(rc);
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync}
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync/**
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * Hashes a plain text password.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * @param a_pstrPassword Plain text password to hash. This is both
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync * input and output.
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsyncvoid VBoxHashPassword(RTCString *a_pstrPassword)
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync{
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync AssertReturnVoid(!VBoxIsPasswordHashed(a_pstrPassword));
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync char szHashedPw[sizeof(s_szHashedPwPrefix) + 1 + RTSHA512_DIGEST_LEN];
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync if (a_pstrPassword->isEmpty())
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync szHashedPw[0] = '\0';
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync else
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync {
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* prefix */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync char *pszHashedPw = szHashedPw;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync strcpy(pszHashedPw, s_szHashedPwPrefix);
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync pszHashedPw += sizeof(s_szHashedPwPrefix) - 1;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* salt */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *pszHashedPw++ = '#'; /* no salt yet */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync /* hash */
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync uint8_t abHash[RTSHA512_HASH_SIZE];
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync RTSha512(a_pstrPassword->c_str(), a_pstrPassword->length(), abHash);
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync int rc = RTSha512ToString(abHash, pszHashedPw, sizeof(szHashedPw) - (pszHashedPw - &szHashedPw[0]));
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync AssertReleaseRC(rc);
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync }
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync *a_pstrPassword = szHashedPw;
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync}
128c985cbcd15f78b4f54364533dee56100dd2a9vboxsync