# HG changeset patch # User bsw # Date 1348403720 -7200 # Node ID e3887fea39fa29f02c0fbc66be91bb47a5eda720 # Parent a176129ce282728ea5169ee8b6ad137b0353802f Added support for SHA-2 based password hashing diff -r a176129ce282 -r e3887fea39fa app/main/index/_action/login.lua --- a/app/main/index/_action/login.lua Sun Aug 26 22:37:49 2012 +0200 +++ b/app/main/index/_action/login.lua Sun Sep 23 14:35:20 2012 +0200 @@ -1,4 +1,7 @@ -local member = Member:by_login_and_password(param.get('login'), param.get('password')) +local login = param.get("login") +local password = param.get("password") + +local member = Member:by_login_and_password(login, password) function do_etherpad_auth(member) local result = net.curl( @@ -59,6 +62,11 @@ else app.session.lang = member.lang end + + if member.password_hash_needs_update then + member:set_password(password) + end + member:save() app.session.member = member app.session:save() diff -r a176129ce282 -r e3887fea39fa config/example.lua --- a/config/example.lua Sun Aug 26 22:37:49 2012 +0200 +++ b/config/example.lua Sun Sep 23 14:35:20 2012 +0200 @@ -99,6 +99,19 @@ -- config.mail_from = { name = "LiquidFeedback", address = "liquidfeedback@example.com" } -- config.mail_reply_to = { name = "Support", address = "support@example.com" } +-- Configuration of password hashing algorithm (defaults to "crypt_sha512") +-- ------------------------------------------------------------------------ +-- config.password_hash_algorithm = "crypt_sha512" +-- config.password_hash_algorithm = "crypt_sha256" +-- config.password_hash_algorithm = "crypt_md5" + +-- Number of rounds for crypt_sha* algorithms, minimum and maximum +-- (defaults to minimum 10000 and maximum 20000) +-- ------------------------------------------------------------------------ +-- config.password_hash_min_rounds = 10000 +-- config.password_hash_max_rounds = 20000 + + -- Supply custom url for avatar/photo delivery -- ------------------------------------------------------------------------ -- config.fastpath_url_func = nil diff -r a176129ce282 -r e3887fea39fa config/init.lua --- a/config/init.lua Sun Aug 26 22:37:49 2012 +0200 +++ b/config/init.lua Sun Sep 23 14:35:20 2012 +0200 @@ -5,6 +5,18 @@ config.app_version = "2.0.5" +if not config.password_hash_algorithm then + config.password_hash_algorithm = "crypt_sha512" +end + +if not config.password_hash_min_rounds then + config.password_hash_min_rounds = 10000 +end + +if not config.password_hash_max_rounds then + config.password_hash_max_rounds = 20000 +end + if config.enabled_languages == nil then config.enabled_languages = { 'en', 'de', 'eo', 'el', 'hu', 'it', 'nl', 'zh-Hans', 'zh-TW' } end diff -r a176129ce282 -r e3887fea39fa model/member.lua --- a/model/member.lua Sun Aug 26 22:37:49 2012 +0200 +++ b/model/member.lua Sun Sep 23 14:35:20 2012 +0200 @@ -271,14 +271,46 @@ function Member.object:set_password(password) trace.disable() + + local hash_prefix + local salt_length + + local function rounds() + return multirand.integer( + config.password_hash_min_rounds, + config.password_hash_max_rounds + ) + end + + if config.password_hash_algorithm == "crypt_md5" then + hash_prefix = "$1$" + salt_length = 8 + + elseif config.password_hash_algorithm == "crypt_sha256" then + hash_prefix = "$5$rounds=" .. rounds() .. "$" + salt_length = 16 + + elseif config.password_hash_algorithm == "crypt_sha512" then + hash_prefix = "$6$rounds=" .. rounds() .. "$" + salt_length = 16 + + else + error("Unknown hash algorithm selected in configuration") + + end + local hash = extos.crypt( password, - "$1$" .. multirand.string( - 8, + hash_prefix .. multirand.string( + salt_length, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./" ) ) - assert(hash, "extos.crypt failed") + + if not hash or hash:sub(1, #hash_prefix) ~= hash_prefix then + error("Password hashing algorithm failed") + end + self.password = hash end @@ -290,6 +322,44 @@ end end +function Member.object_get:password_hash_needs_update() + + if self.password == nil then + return nil + end + + local function check_rounds(rounds) + if rounds then + rounds = tonumber(rounds) + if + rounds >= config.password_hash_min_rounds and + rounds <= config.password_hash_max_rounds + then + return false + end + end + return true + end + + if config.password_hash_algorithm == "crypt_md5" then + + return self.password:sub(1,3) ~= "$1$" + + elseif config.password_hash_algorithm == "crypt_sha256" then + + return check_rounds(self.password:match("^%$5%$rounds=([1-9][0-9]*)%$")) + + elseif config.password_hash_algorithm == "crypt_sha512" then + + return check_rounds(self.password:match("^%$6%$rounds=([1-9][0-9]*)%$")) + + else + error("Unknown hash algorithm selected in configuration") + + end + +end + function Member.object_get:published_contacts() return Member:new_selector() :join('"contact"', nil, '"contact"."other_member_id" = "member"."id"')