Init
This commit is contained in:
193
DependentExtensions/cat/crypt/pass/Passwords.hpp
Normal file
193
DependentExtensions/cat/crypt/pass/Passwords.hpp
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CAT_PASSWORDS_HPP
|
||||
#define CAT_PASSWORDS_HPP
|
||||
|
||||
#include <cat/rand/IRandom.hpp>
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
/*
|
||||
Why are passwords needed?
|
||||
|
||||
Passwords allow the client identity to be proved to the server. Usually
|
||||
the server identity is already proven by a secure connection, but the
|
||||
client identity is unproven until a password is provided.
|
||||
|
||||
This could be done using signatures with two-way authentication in the
|
||||
secure connection establishment, however this is very slow and roughly
|
||||
doubles the work a server has to do to accept a connection.
|
||||
|
||||
Passwords seem simple to implement at first but then you start imagining all
|
||||
the "what ifs":
|
||||
|
||||
What if the password database is stolen?
|
||||
|
||||
The user passwords had better not be stored in plaintext!
|
||||
So they must be hashed.
|
||||
|
||||
What if two users have the same password?
|
||||
|
||||
They would look the same hashed, so hash in the name with the password.
|
||||
|
||||
What if name:password for two users is "me : pass" and "m : epass" ?
|
||||
|
||||
They would look the same hashed, so insert a separator between the two
|
||||
before hashing, as in "me\r\npass" instead of just hashing "mepass".
|
||||
|
||||
What if someone tries to crack the passwords?
|
||||
|
||||
The password hash should be strengthened to make it harder to crack,
|
||||
by applying the hash function repeatedly. This does reduce the number of
|
||||
bits of entropy due to non-ideal hash function collisions, but this small
|
||||
effect is offset by the added difficulty to crack the password.
|
||||
|
||||
What if the user has a common name like "dave"?
|
||||
|
||||
The password hash should be salted to avoid falling to rainbow tables.
|
||||
|
||||
What if the attacker tries to use the stolen password hash to log into the server?
|
||||
|
||||
The client provides a hash pre-image during login, so the attacker would need
|
||||
to reverse the hash to do this, which is harder than cracking the password.
|
||||
|
||||
What if an attacker has a way to actively or passively listen to login attempts?
|
||||
|
||||
Then they would be able to steal the hash pre-image which would offer some
|
||||
amount of text password protection but would allow the attacker to log in
|
||||
as the user without knowing the password.
|
||||
|
||||
Rainbow tables can be used to crack the pre-image to determine the password.
|
||||
|
||||
If the connection is secure then the client has verified the server identity
|
||||
and these attacks are only possible through software bugs in the server.
|
||||
|
||||
|
||||
Protocol Description:
|
||||
|
||||
H: 256-bit hash function Skein-256
|
||||
c: Client
|
||||
s: Server
|
||||
X: Strengthening factor
|
||||
|
||||
|
||||
Protocol 1: Creating a User Account
|
||||
|
||||
c: Choose a name N
|
||||
c: Choose a password P
|
||||
c: Calculate I = H("N\r\nP") strengthened X times
|
||||
|
||||
c2s CREATE_ACCOUNT || N || I (32 by)
|
||||
|
||||
s: Verify account is not taken, then creates an account in the database
|
||||
s: Generate a 32-bit random salt S
|
||||
s: Calculate J = H(S || I)
|
||||
s: Store N, J and S in the account
|
||||
|
||||
s2c ACCOUNT_CREATE_SUCCESS
|
||||
|
||||
|
||||
Protocol 2: Logging into a User Account
|
||||
|
||||
c: Choose a name N
|
||||
c: Choose a password P
|
||||
c: Calculate I = H("N\r\nP") strengthened X times
|
||||
|
||||
c2s LOGIN_REQUEST || N || I (32 by)
|
||||
|
||||
s: Verify user name exists in account database
|
||||
s: Retrieve J, S from the account database
|
||||
s: Calculate J' = H(S || I)
|
||||
s: Verify J = J'
|
||||
|
||||
s2c LOGIN_SUCCESS
|
||||
|
||||
|
||||
What if the user creates an account through a website?
|
||||
|
||||
The server-side script on the website should execute a program that runs
|
||||
Protocol 1 to create the user account.
|
||||
|
||||
Why use this sort of password authentication + Tunnel instead of SRP?
|
||||
|
||||
Performance. The Tunnel key agreement takes much less CPU time than SRP
|
||||
and authenticates the server, which allows this protocol to be run without
|
||||
any disadvantages.
|
||||
*/
|
||||
|
||||
|
||||
class PasswordBase
|
||||
{
|
||||
public:
|
||||
static const int HASH_BITS = 256;
|
||||
static const int HASH_BYTES = HASH_BITS / 8;
|
||||
static const int STRENGTHENING_FACTOR = 1000;
|
||||
};
|
||||
|
||||
|
||||
class PasswordCreator : public PasswordBase
|
||||
{
|
||||
public:
|
||||
// Hash a password for transmission to the server during account creation or login
|
||||
// NOTE: You should make the name all lowercase before passing it in
|
||||
// Returns false on failure
|
||||
bool HashPassword(const void *in_name, int name_bytes,
|
||||
const void *in_password, int password_bytes,
|
||||
void *out_hash /* 32 bytes */);
|
||||
|
||||
// This version accepts non-unicode C strings with nul-terminators
|
||||
// It converts the name to lowercase internally
|
||||
bool HashPasswordString(const char *in_name,
|
||||
const char *in_password,
|
||||
void *out_hash /* 32 bytes */);
|
||||
};
|
||||
|
||||
class PasswordVerifier : public PasswordBase
|
||||
{
|
||||
public:
|
||||
// Salt a hash for storage in the account database during account creation
|
||||
// Generates a 32-bit salt and a 256-bit hash for storage
|
||||
// Returns false on failure
|
||||
bool SaltHash(IRandom *prng,
|
||||
const void *in_hash /* 32 bytes */,
|
||||
void *out_salted_hash /* 32 bytes */,
|
||||
u32 *out_salt /* 4 bytes */);
|
||||
|
||||
// Given the stored salted hash and salt, verify the client's password hash during login
|
||||
// Returns false if password is incorrect
|
||||
bool VerifyHash(const void *in_hash /* 32 bytes */,
|
||||
const void *in_salted_hash /* 32 bytes */,
|
||||
u32 in_salt /* 4 bytes */);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_PASSWORDS_HPP
|
||||
Reference in New Issue
Block a user