return rc == 1;
}
-bool ComparePassword(const String hash, const String password, const String salt)
+bool ComparePassword(const String& hash, const String& password, const String& salt)
{
- String otherHash = HashPassword(password, salt);
+ String otherHash = PBKDF2_SHA256(password, salt, 1000);
+ VERIFY(otherHash.GetLength() == 64 && hash.GetLength() == 64);
const char *p1 = otherHash.CStr();
const char *p2 = hash.CStr();
+ /* By Novelocrat, https://stackoverflow.com/a/25374036 */
volatile char c = 0;
- for (size_t i=0; i<64; ++i)
+ for (size_t i = 0; i < 64; ++i)
c |= p1[i] ^ p2[i];
return (c == 0);
}
-String HashPassword(const String& password, const String& salt, const bool shadow)
+/* Returns a String in the format $algorithm$salt$hash or returns an empty string in case of an error */
+String CreateHashedPasswordString(const String& password, const String& salt, int algorithm)
{
- if (shadow)
- //Using /etc/shadow password format. The 5 means SHA256 is being used
- return String("$5$" + salt + "$" + PBKDF2_SHA256(password, salt, 1000));
- else
- return PBKDF2_SHA256(password, salt, 1000);
+ // We currently only support SHA256
+ if (algorithm != 5)
+ return String();
+
+ if (salt.FindFirstOf('$') != String::NPos)
+ return String();
+
+ return String("$5$" + salt + "$" + PBKDF2_SHA256(password, salt, 1000));
}
}
String I2_BASE_API SHA256(const String& s);
String I2_BASE_API RandomString(int length);
bool I2_BASE_API VerifyCertificate(const boost::shared_ptr<X509>& caCertificate, const boost::shared_ptr<X509>& certificate);
-bool I2_BASE_API ComparePassword(const String hash, const String password, const String Salt);
-String I2_BASE_API HashPassword(const String& password, const String& salt, const bool shadow = false);
+bool ComparePassword(const String& hash, const String& password, const String& Salt);
+String CreateHashedPasswordString(const String& password, const String& salt, int algorithm = 5);
class I2_BASE_API openssl_error : virtual public std::exception, virtual public boost::exception { };
{
visibleDesc.add_options()
("user", po::value<std::string>(), "API username")
- ("passwd", po::value<std::string>(), "Password in clear text")
+ ("password", po::value<std::string>(), "Password in clear text")
("salt", po::value<std::string>(), "Optional salt (default: 8 random chars)")
("oneline", "Print only the password hash");
}
} else
user = vm["user"].as<std::string>();
- if (!vm.count("passwd")) {
- Log(LogCritical, "cli", "Password (--passwd) must be specified.");
+ if (!vm.count("password")) {
+ Log(LogCritical, "cli", "Password (--password) must be specified.");
return 1;
}
return 1;
}
- String hashedPassword = HashPassword(passwd, salt, true);
+ String hashedPassword = CreateHashedPasswordString(passwd, salt, 5);
+ if (hashedPassword == String()) {
+ Log(LogCritical, "cli") << "Failed to hash password \"" << passwd << "\" with salt \"" << salt << "\"";
+ return 1;
+ }
if (vm.count("oneline"))
std::cout << '"' << hashedPassword << "\"\n";
{
ObjectImpl<ApiUser>::OnConfigLoaded();
- if (this->GetPasswordHash().IsEmpty())
- SetPasswordHash(HashPassword(GetPassword(), RandomString(8), true));
+ if (GetPasswordHash().IsEmpty()) {
+ String hashedPassword = CreateHashedPasswordString(GetPassword(), RandomString(8), 5);
+ VERIFY(hashedPassword != String());
+ SetPasswordHash(hashedPassword);
+ SetPassword("********");
+ }
}
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)