char* tr_ssha1( const void * plaintext ) { enum { saltval_len = 8, salter_len = 64 }; static const char * salter = "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "./"; size_t i; unsigned char salt[saltval_len]; uint8_t sha[SHA_DIGEST_LENGTH]; char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2]; tr_cryptoRandBuf( salt, saltval_len ); for( i=0; i<saltval_len; ++i ) salt[i] = salter[ salt[i] % salter_len ]; tr_sha1( sha, plaintext, strlen( plaintext ), salt, saltval_len, NULL ); tr_sha1_to_hex( &buf[1], sha ); memcpy( &buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len ); buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0'; buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring easier */ return tr_strdup( &buf ); }
tr_bool tr_ssha1_matches( const char * source, const char * pass ) { char * salt; size_t saltlen; char * hashed; uint8_t buf[SHA_DIGEST_LENGTH]; tr_bool result; /* extract the salt */ saltlen = strlen( source ) - 2*SHA_DIGEST_LENGTH-1; salt = tr_malloc( saltlen ); memcpy( salt, source + 2*SHA_DIGEST_LENGTH+1, saltlen ); /* hash pass + salt */ hashed = tr_malloc( 2*SHA_DIGEST_LENGTH + saltlen + 2 ); tr_sha1( buf, pass, strlen( pass ), salt, saltlen, NULL ); tr_sha1_to_hex( &hashed[1], buf ); memcpy( hashed + 1+2*SHA_DIGEST_LENGTH, salt, saltlen ); hashed[1+2*SHA_DIGEST_LENGTH + saltlen] = '\0'; hashed[0] = '{'; result = strcmp( source, hashed ) == 0 ? TRUE : FALSE; tr_free( hashed ); tr_free( salt ); return result; }
static int test_hex (void) { char hex1[41]; char hex2[41]; uint8_t sha1[20]; memcpy (hex1, "fb5ef5507427b17e04b69cef31fa3379b456735a", 41); tr_hex_to_sha1 (sha1, hex1); tr_sha1_to_hex (hex2, sha1); check_streq (hex1, hex2); return 0; }