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

Content deleted Content added
PureFox (talk | contribs)
Added Wren
PureFox (talk | contribs)
m →‎{{header|Wren}}: Minor tidy and rerun
 
(2 intermediate revisions by 2 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}}==
Line 904 ⟶ 937:
{{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.
<langsyntaxhighlight ecmascriptlang="wren">import "os" for Process
import "./long" for ULong
import "./crypto" for Bytes, Sha1, Sha256, Hmac
Line 980 ⟶ 1,013:
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))</langsyntaxhighlight>
 
{{out}}
Line 986 ⟶ 1,019:
<pre>
$ date '+%s'
1707913906
1638830494
$ wren-cli totpTime-based_one-time_password_algorithm.wren 16388304941707913906
260040
38559208
24454221
185760458
189816119
556237229
499920719
</pre>
 
Line 997 ⟶ 1,030:
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 1,033 ⟶ 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 1,061 ⟶ 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 1,074 ⟶ 1,107:
Atomic.sleep(10);
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,091 ⟶ 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,104 ⟶ 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>