Created
May 15, 2014 07:27
-
-
Save bellbind/87c0caf6c48cfd26ddf6 to your computer and use it in GitHub Desktop.
[nodejs]Understanding S/Key style One-time password system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// S/Key style One-time Password system | |
var crypto = require("crypto"); | |
// [functions for OTP system] | |
// generate server info of one time password | |
var initAccount = function (passphrase) { | |
var alg = "sha256"; | |
var enc = "hex"; | |
var times = 100; | |
var seed = crypto.randomBytes(10).toString(enc); | |
var otp = seed + passphrase; | |
for (var i = 0; i < times; i++) { | |
var hash = crypto.createHash(alg); | |
otp = hash.update(otp).digest(enc); | |
} | |
return { | |
seed: seed, | |
times: times, | |
otp: otp, | |
alg: alg, | |
enc: enc, | |
}; | |
}; | |
// create message to client | |
var otpMessage = function (account) { | |
if (account.times <= 1) return null; // require to re-initialize seed | |
return { | |
seed: account.seed, | |
times: account.times - 1, | |
alg: account.alg, | |
enc: account.enc, | |
}; | |
}; | |
// generate OTP at clients | |
var generateOtp = function (message, passphrase) { | |
var otp = message.seed + passphrase; | |
for (var i = 0; i < message.times; i++) { | |
var hash = crypto.createHash(message.alg); | |
otp = hash.update(otp).digest(message.enc); | |
} | |
return otp; | |
}; | |
// check OTP is valid at server | |
var checkOtp = function (account, otp) { | |
var hash = crypto.createHash(account.alg); | |
var valid = hash.update(otp).digest(account.enc) === account.otp; | |
if (valid) { | |
// drop previous valid otp | |
account.otp = otp; | |
account.times -= 1; | |
return true; | |
} | |
return false; | |
}; | |
////////////////////////////////////////////////////////////////////// | |
// [case of otp flow] | |
var main = function () { | |
// [start] | |
var client = {pass: "Hello"}; | |
var server = initAccount(client.pass); | |
// [first session] | |
// client requests info for server | |
var msg = otpMessage(server); | |
// client gerenates otp | |
var otp = generateOtp(msg, client.pass); | |
// server checks otp | |
var result = checkOtp(server, otp); // => true | |
console.log("generated otp success: " + result); | |
// server checks stolen otp | |
var result = checkOtp(server, otp); // => false | |
console.log("reused otp fail: " + result); | |
// [next session] | |
// client requests info for server | |
var msg = otpMessage(server); | |
// client gerenates otp | |
var otp = generateOtp(msg, client.pass); | |
// server checks otp | |
var result = checkOtp(server, otp); // => true | |
console.log("generated otp success: " + result); | |
}; | |
main(); |
[Key Concept of S/Key style OTP system]
At first, The server holds multiply(n times) applied hash function to the client shared key. e.g.
- On Server: [n, H(H(...H(Key)...))]
When The client request for auth, the server respond times as "n-1".
- (from Server) Auth Request: [n-1]
The client calculate and respond n-1 times applied the hash function to the shared key.
- (from Client) Auth Response: [H(...(H(Key)...)]
The server apply the hash function to the auth response and compare stored value
- H(Auth Response) == H(H.(...H(Key)...))
If comparation success,
then update the server stored value to the Auth Response as the n-1 hashed key
(== the old password dropped forever as ONE TIME),
and the server perform authentication succeeded.
- On Server: [n-1, H(...H(Key)...)]
If comparation failed, then the server just perform authentication failed.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As a OTP System,
but