Time-based one-time password algorithm: Difference between revisions

m
→‎{{header|Wren}}: Minor tidy and rerun
m (→‎{{header|Wren}}: Minor tidy and rerun)
 
(3 intermediate revisions by 3 users not shown)
Line 31:
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Security.Cryptography;
 
Line 92:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Caché ObjectScript}}==
 
<langsyntaxhighlight lang="cos">
Class Utils.Security [ Abstract ]
{
Line 182:
 
}
</syntaxhighlight>
</lang>
{{out|Example}}
<pre>
Line 200:
=={{header|Go}}==
A slightly [https://github.com/gwwfps/onetime/pull/1 fixed] version of a [https://github.com/gwwfps/onetime package by Zitao Zhang] (released under a [https://github.com/gwwfps/onetime/blob/master/LICENSE simplified BSD license]).
<langsyntaxhighlight lang="go">// Package onetime provides a library for one-time password generation,
// implementing the HOTP and TOTP algorithms as specified by IETF RFC-4226
// and RFC-6238.
Line 273:
p[0] &= 0x7f
return p
}</langsyntaxhighlight>
{{out|Example use}}
(in a format that gets put into the [https://godoc.org/github.com/dchapes/onetime generated documentation])
<langsyntaxhighlight lang="go">package onetime
 
import (
Line 314:
var code = otp.TOTP(secret)
fmt.Println(code)
}</langsyntaxhighlight>
 
=={{header|J}}==
<syntaxhighlight lang="j">DA =: '0123456789ABCDEF'
to_bytes =: 16 16#.(2,~2%~#)$ DA i. ]
upper =: 1&(3!:12)
xor =: 22 b.
and =: 17 b.
 
hmac_sha1 =: {{
sha1 =. _1&(128!:6)
 
b_size =. 512 % 8
 
pad_key =. b_size {.]
 
block_sized_key =. pad_key a.&i. x
o_key_pad =. block_sized_key xor b_size $ 16b5c
i_key_pad =. block_sized_key xor b_size $ 16b36
 
hashed =. sha1 (i_key_pad { a.), y
a. i. sha1 (o_key_pad { a.), hashed }}
 
totp =: {{
h =. x hmac_sha1&:(a. {~ to_bytes&]) y
offset =. 16bf and {: h
1000000|16b7fffffff and (4$256)#. 4 {. offset |. h }}
</syntaxhighlight>
 
{{out|Example use}}
<syntaxhighlight lang="j">time =: '0000000000000001' NB. 64-bit timestamp in hex format
secrete =: 'AB54A98CEB1F0AD2' NB. secrete key in hex format
time totp secrete NB. 758742
</syntaxhighlight>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">using CodecBase
using SHA
 
Line 355 ⟶ 388:
sleep(15)
end
</langsyntaxhighlight>{{out}}
<pre>
656601
Line 372 ⟶ 405:
Note that due to the interface of the hash function in module “std/sha1”, we have chosen to work with sequences of characters rather than sequences of bytes. The other way is of course possible, but maybe less convenient.
 
<langsyntaxhighlight Nimlang="nim">import endians, math, sequtils, std/sha1, times
 
type
Line 470 ⟶ 503:
 
echo "Google authenticator:"
exampleAuthenticator()</langsyntaxhighlight>
 
{{out}}
Line 480 ⟶ 513:
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight Perllang="perl"># 20200704 added Perl programming solution
 
use strict;
Line 493 ⟶ 526:
for ( my $t = 2177452800 ; $t < 2177452919 ; $t += 13 ) {
print "At ", scalar gmtime $t, " : ", $oath->totp( $message, $t ), "\n" ;
}</langsyntaxhighlight>
{{out}}
<pre>
Line 511 ⟶ 544:
{{trans|Perl}}
Note the byte ordering of hmac (etc) is suspect and may change, hence bmap below
<!--<langsyntaxhighlight Phixlang="phix">-->
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.1"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- sha1.e added</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">sha1</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
Line 544 ⟶ 577:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"At %s : %06d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">totp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">message</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 561 ⟶ 594:
=={{header|PicoLisp}}==
Using the <tt>sha1</tt> function defined at ''[[SHA-1#PicoLisp]]'':
<langsyntaxhighlight PicoLisplang="picolisp">(load "sha1.l")
 
(de hmac ("Fun" Msg Key)
Line 614 ⟶ 647:
(test
(cdr L)
(totp (mapcar char (chop "12345678901234567890")) (car L) 8) ) )</langsyntaxhighlight>
 
=={{header|Racket}}==
This includes BASE32 encoding, token based authentication and other such stuff.
 
<langsyntaxhighlight lang="racket">#lang racket
(require (only-in web-server/stuffers/hmac-sha1 HMAC-SHA1))
 
Line 762 ⟶ 795:
(base32-encode-bytes #"Super Secret Password Key 88!")
=> #"KN2XAZLSEBJWKY3SMV2CAUDBONZXO33SMQQEWZLZEA4DQII="
))</langsyntaxhighlight>
 
{{out}}
Line 780 ⟶ 813:
(formerly Perl 6)
This is a minimal attempt that covers only the "Time-based" part of the requirement.
<syntaxhighlight lang="raku" perl6line># Reference:
# https://github.com/retupmoca/P6-Digest-HMAC
 
Line 803 ⟶ 836:
say totp $message, DateTime.new(now);
}
</syntaxhighlight>
</lang>
{{out}}
<pre>Deterministic output at 2039-01-01T00:00:00Z with fixed checks,
Line 824 ⟶ 857:
This TOTP/HOTP module clocks in small by taking advantage of [https://core.tcl.tk/tcllib/doc/trunk/embedded/www/toc.html tcllib's] existing hashing and base32 modules.
 
<syntaxhighlight lang="tcl">
<lang Tcl>
# rfc6238 contains examples of hotp with 8-digit modulus and sha1/sha256/sha512 hmac
#
Line 895 ⟶ 928:
}
assert {{306281 553572 304383} eq [google 1400000000]}
}</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-long}}
{{libheader|Wren-crypto}}
{{libheader|Wren-date}}
{{libheader|Wren-srandom}}
As Wren-cli currently has no way of determining the Unix time, this needs to be input as a command line parameter so we can track it from there.
<syntaxhighlight lang="wren">import "os" for Process
import "./long" for ULong
import "./crypto" for Bytes, Sha1, Sha256, Hmac
import "./date" for Date
import "./srandom" for SRandom
 
var StartTime = null // time program was started (as a Unix timestamp)
 
class OneTimePassword {
construct new(digit, timeStep, baseTime, hashClass) {
_digit = digit // length of code generated
_timeStep = timeStep // length of each time step for TOTP
_baseTime = baseTime // start time for TOTP step calculation (as a Unix timestamp)
_hashClass = hashClass // hash class to be used with HMAC
}
 
// Convenience version of above which uses defaults values for all except 'digit' parameter.
static simple(digit) { new(digit, 30, 0, Sha1) }
// Returns a HOTP code with the given secret and counter.
hotp(secret, count) { truncate_(hmacSum_(secret, count)) }
 
// Returns a TOTP code calculated with the current time and the given secret.
totp(secret) { hotp(secret, steps_(timeNow_)) }
 
/* private helper methods */
 
hmacSum_(secret, count) {
var msg = ULong.new(count).toBytes[-1..0] // big-endian
return Bytes.fromHexString(Hmac.digest(secret, msg, Sha1))
}
 
dt_(hs) {
var offset = hs[-1] & 0xf
var p = hs[offset...offset+4]
p[0] = p[0] & 0x7f
return p
}
 
truncate_(hs) {
var sbits = dt_(hs)
var snum = Bytes.toIntBE(sbits)
var pwr = 10.pow(_digit)
return snum % pwr
}
 
steps_(now) { ((now - _baseTime)/_timeStep).floor }
 
timeNow_ { (StartTime + System.clock).floor }
}
 
var args = Process.arguments
if (args.count != 1) {
System.print("Please pass the Unix timestamp when starting the program.")
return
}
StartTime = Num.fromString(args[0])
var secret = "SOME_SECRET".bytes.toList
 
// Simple 6-digit HOTP code.
var otp = OneTimePassword.simple(6)
System.print(otp.hotp(secret, 123456))
 
// Google authenticator style 8-digit TOTP code.
otp = OneTimePassword.simple(8)
System.print(otp.totp(secret))
 
// Custom 9 digit, 5 second step TOTP starting on midnight 2000-01-01 UTC, using Sha256.
var baseTime = Date.new(2000, 1, 1).unixTime
otp = OneTimePassword.new(9, 5, baseTime, Sha256)
System.print(otp.totp(secret))
 
// As above using a random, 32 byte, Base32 key
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" // for Base32
var randKey = List.filled(32, null)
for (i in 0..31) randKey[i] = alphabet[SRandom.int(32)]
System.print(otp.totp(randKey.join().bytes.toList))</syntaxhighlight>
 
{{out}}
Sample output:
<pre>
$ date '+%s'
1707913906
$ wren-cli Time-based_one-time_password_algorithm.wren 1707913906
260040
38559208
185760458
556237229
</pre>
 
=={{header|zkl}}==
Uses the MsgHash dll, which includes SHA-1, SHA-256 hashes and HMAC routines for SHA-* and MD5.
{{trans|Go}}
<langsyntaxhighlight lang="zkl">var [const] MsgHash = Import.lib("zklMsgHash");
// OneTimePassword stores the configuration values relevant to HOTP/TOTP calculations.
Line 936 ⟶ 1,066:
fcn totp(secret){ hotp(secret, steps(Time.Clock.time())) }
fcn steps(now) { (now - baseTime)/timeStep } // elapsed time chunked
} // OneTimePassword</langsyntaxhighlight>
Note: MsgHash hashes return a string by default, they can also return the hash as bytes. Ditto the HMAC routines, it is the third parameter. So, to create a hmac that returns bytes, use (eg) MsgHash.extra.hmacSHA1.fp2(False), this creates a partial application (closure) of the hmac using SHA-1 fixing the third parameter as False.
{{out|Example uses}}
<langsyntaxhighlight lang="zkl">fcn example_simple{
// Simple 6-digit HOTP code:
secret := "SOME_SECRET";
Line 964 ⟶ 1,094:
code := otp.totp(secret);
println(code) //-->eg 707355416
}();</langsyntaxhighlight>
{{out|Example use}}
Showing how to sync with changes over time. A six digit OTP w/MD5 changing every 17 seconds. Latency can effect the result when totp is called at a time boundary, so a retry may be required.
<langsyntaxhighlight lang="zkl">fcn overTime{
secret,ts:= "SOME_SECRET",17;
otp := OneTimePassword(6,ts,Time.Clock.time(),MsgHash.extra.hmacMD5.fp2(False));
Line 977 ⟶ 1,107:
Atomic.sleep(10);
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 994 ⟶ 1,124:
{{out|HMAC code}}
The MsgHash HMAC routines are pretty simple (the hash code is C), included here for completeness:
<langsyntaxhighlight lang="zkl">// https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
fcn hmac(key,msg,hashFcn,asString){
blkSz,H,Hx := 64,hashFcn.fp1(1,Data()), (asString and hashFcn or H);
Line 1,007 ⟶ 1,137:
fcn hmacSHA1( key,msg,asString=True){ hmac(key,msg,MsgHash.SHA1, asString) }
fcn hmacSHA256(key,msg,asString=True){ hmac(key,msg,MsgHash.SHA256,asString) }
fcn hmacMD5( key,msg,asString=True){ hmac(key,msg,Utils.MD5.calc,asString) }</langsyntaxhighlight>
9,476

edits