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

m
→‎{{header|Wren}}: Minor tidy and rerun
m (added hightlighing.)
m (→‎{{header|Wren}}: Minor tidy and rerun)
 
(7 intermediate revisions by 6 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 365 ⟶ 398:
514592
</pre>
 
=={{header|Nim}}==
{{trans|Go}}
We borrowed the HMAC function from Julia solution, but didn’t apply a hash on the key at beginning. This way, we obtain the same result as Go for the “Simple” example.
 
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.
 
<syntaxhighlight lang="nim">import endians, math, sequtils, std/sha1, times
 
type
 
HashFunc = proc(msg: openArray[char]): seq[char]
 
OneTimePassword = object
digit: int # Length of code generated.
timeStep: Duration # Length of each time step for TOTP.
baseTime: Time # The start time for TOTP step calculation.
hash: HashFunc # Hash algorithm used with HMAC.
 
 
func sha1Hash(msg: openArray[char]): seq[char] =
mapIt(@(Sha1Digest(secureHash(msg))), char(it))
 
 
func `xor`(s: seq[char]; val: byte): seq[char] =
## Apply a XOR to the chars of a sequence.
s.mapIt(char(it.byte xor val))
 
 
func hmac(key, msg: openArray[char]; hashFunc: HashFunc; blockSize = 64): seq[char] =
## Compute a HMAC for gien key, message, hash function and block size.
var key = @key
let paddingNeeded = blockSize - key.len
if paddingNeeded > 0: key.setLen(blockSize)
result = hashFunc((key xor 0x5c) & hashFunc((key xor 0x36) & @msg))
 
 
func simple(digit: int): OneTimePassword =
## Return a new OneTimePassword with the specified HTOP code length,
## SHA-1 as the HMAC hash algorithm, the Unix epoch as the base time, and
## 30 seconds as the step length.
doAssert digit in 6..9, "HTOP code length must be in 6..9."
let step = initDuration(seconds = 30)
result = OneTimePassword(digit: digit, timeStep: step, baseTime: fromUnix(0), hash: sha1Hash)
 
 
func hmacSum(otp: OneTimePassword; secret: openArray[char]; count: uint64): seq[char] =
var count = count
var beCount: uint64
bigEndian64(beCount.addr, count.addr)
let msg = cast[array[8, char]](beCount)
result = hmac(secret, msg, otp.hash)
 
 
func dt(hs: seq[char]): seq[char] =
let offset = hs[^1].byte and 0xf
result = hs[offset..offset+3]
result[0] = char(result[0].byte and 0x7f)
 
 
func truncate(otp: OneTimePassword; hs: seq[char]): uint64 =
let sbits = dt(hs)
let snum = sbits[3].uint64 or sbits[2].uint64 shl 8 or
sbits[1].uint64 shl 16 or sbits[0].uint64 shl 24
result = snum mod 10u^otp.digit
 
 
func hotp(otp: OneTimePassword; secret: openArray[char]; count: uint64): uint64 =
let hs = otp.hmacSum(secret, count)
result = otp.truncate(hs)
 
 
func steps(otp: OneTimePassword; t: Time): uint64 =
let elapsed = t - otp.baseTime
result = uint64(elapsed.inSeconds div otp.timeStep.inSeconds)
 
 
proc totp(otp: OneTimePassword; secret: openArray[char]): uint64 =
## Return a TOTP code calculated with the current time and the given secret.
otp.hotp(secret, otp.steps(getTime()))
 
 
when isMainModule:
 
proc exampleSimple =
## Simple 6-digit HOTP code.
const secret = "SOME_SECRET"
var counter: uint64 = 123456
let otp = simple(6)
let code = otp.hotp(secret, counter)
echo code
# Output:
# 260040
 
proc exampleAuthenticator =
## Google authenticator style 8-digit TOTP code.
const secret = "SOME_SECRET"
let otp = simple(8)
let code = otp.totp(secret)
echo code
 
echo "Simple:"
exampleSimple()
 
echo "Google authenticator:"
exampleAuthenticator()</syntaxhighlight>
 
{{out}}
<pre>Simple:
260040
Google authenticator:
94364703</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight Perllang="perl"># 20200704 added Perl programming solution
 
use strict;
Line 381 ⟶ 526:
for ( my $t = 2177452800 ; $t < 2177452919 ; $t += 13 ) {
print "At ", scalar gmtime $t, " : ", $oath->totp( $message, $t ), "\n" ;
}</langsyntaxhighlight>
{{out}}
<pre>
Line 394 ⟶ 539:
At Sat Jan 1 00:01:44 2039 : 341623
At Sat Jan 1 00:01:57 2039 : 341623
</pre>
 
=={{header|Phix}}==
{{trans|Perl}}
Note the byte ordering of hmac (etc) is suspect and may change, hence bmap below
<!--<syntaxhighlight lang="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>
<span style="color: #008080;">include</span> <span style="color: #000000;">hmac</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">bmap</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">16</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15</span><span style="color: #0000FF;">,</span><span style="color: #000000;">14</span><span style="color: #0000FF;">,</span><span style="color: #000000;">13</span><span style="color: #0000FF;">,</span><span style="color: #000000;">20</span><span style="color: #0000FF;">,</span><span style="color: #000000;">19</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span><span style="color: #000000;">17</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">dt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bmap</span><span style="color: #0000FF;">[$]],</span><span style="color: #000000;">#0F</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">*</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">+</span><span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bmap</span><span style="color: #0000FF;">[</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7F</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">digits</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">totp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">int_to_bytes</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">/</span><span style="color: #000000;">30</span><span style="color: #0000FF;">),</span><span style="color: #000000;">8</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">hmac_sha1</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">dt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #000000;">set_timedate_formats</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Mmm dth yyyy h:mm:ss"</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">timedate</span> <span style="color: #000000;">td0</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_date_string</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Jan 1st 1970 00:00:00"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">message</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"show me the monKey"</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2177452800</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">13</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">format_timedate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">adjust_timedate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">td0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t</span><span style="color: #0000FF;">))</span>
<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>
<!--</syntaxhighlight>-->
{{out}}
<pre>
At Jan 1st 2039 0:00:00 : 950428
At Jan 1st 2039 0:00:13 : 950428
At Jan 1st 2039 0:00:26 : 950428
At Jan 1st 2039 0:00:39 : 361382
At Jan 1st 2039 0:00:52 : 361382
At Jan 1st 2039 0:01:05 : 022576
At Jan 1st 2039 0:01:18 : 022576
At Jan 1st 2039 0:01:31 : 341623
At Jan 1st 2039 0:01:44 : 341623
At Jan 1st 2039 0:01:57 : 341623
</pre>
 
=={{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 451 ⟶ 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 599 ⟶ 795:
(base32-encode-bytes #"Super Secret Password Key 88!")
=> #"KN2XAZLSEBJWKY3SMV2CAUDBONZXO33SMQQEWZLZEA4DQII="
))</langsyntaxhighlight>
 
{{out}}
Line 617 ⟶ 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 640 ⟶ 836:
say totp $message, DateTime.new(now);
}
</syntaxhighlight>
</lang>
{{out}}
<pre>Deterministic output at 2039-01-01T00:00:00Z with fixed checks,
Line 661 ⟶ 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 669 ⟶ 865:
namespace eval ::totp {
package require sha1
 
oo::class create totp {
variable Secret
Line 698 ⟶ 894:
hotp $Secret $bytes
}
 
}
 
proc hotp {secret bytes {length 6}} {
set hmac [sha1::hmac -bin $secret $bytes]
set ofs [string index $hmac end]
Line 708 ⟶ 904:
set chunk [string range $hmac $ofs $ofs+4]
binary scan $chunk I code
return [format %0${length}.${length}d [expr {($code & 0x7fffffff) % 100000010 ** $length}]]
}
 
}
namespace export *
}
Line 731 ⟶ 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 772 ⟶ 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 800 ⟶ 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 813 ⟶ 1,107:
Atomic.sleep(10);
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 830 ⟶ 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 843 ⟶ 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,479

edits