XLFSHAN ;ISL/PKR SHA secure hash routines. ;09/30/2016
;;8.0;KERNEL;**657**;Jul 10, 1995;Build 9
;Per VA Directive 6402, this routine should not be modified.
Q
;=============================
AND(X,Y) ;Bitwise logical AND, 32 bits. IA #6157
Q $ZBOOLEAN(X,Y,1) ;Cache
;N IND,XA
;S XA=0
;F IND=1:1:32 S XA=(XA\2)+((((X#2)+(Y#2))\2)*2147483648),X=X\2,Y=Y\2
;Q XA
;
;=============================
CHASHLEN(HASHLEN) ;Make sure the hash length is one of the acceptable
;values.
I HASHLEN=160 Q 1
I HASHLEN=224 Q 1
I HASHLEN=256 Q 1
I HASHLEN=384 Q 1
I HASHLEN=512 Q 1
Q 0
;
;=============================
CPUTIME() ;Returns two comma-delimited pieces, "system" CPU time and "user"
;CPU time (except on VMS where no separate times are available).
;Time is returned as milliseconds of CPU time.
Q $SYSTEM.Process.GetCPUTime()
;GT.M
;Q $ZGETJPI("","CPUTIM")*10
;
;=============================
ETIMEMS(START,END) ;Calculate and return the elapsed time in milliseconds.
;START and STOP times are set by calling $$CPUTIME.
N ETIME,TEXT
S END=$P(END,",",2)
S START=$P(START,",",2)
S ETIME=END-START
S TEXT=ETIME_" milliseconds"
Q TEXT
;
;=============================
FILE(HASHLEN,FILENUM,IEN,FIELD,FLAGS) ;Return a SHA hash for the specified
;file entry. IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
N IENS,IND,FIELDNUM,FNUM,HASH,MSG,NBLOCKS,NL,TARGET,TEMP,TEXT,WPI,WPZN
K ^TMP($J,"XLFDIQ"),^TMP($J,"XLFMSG")
S TARGET=$NA(^TMP($J,"XLFDIQ"))
S WPI=$P(TARGET,")",1)
S FLAGS=$G(FLAGS)
S WPZN=$S(FLAGS["Z":1,1:0)
I $G(FIELD)="" S FIELD="**"
D GETS^DIQ(FILENUM,IEN,FIELD,FLAGS,TARGET,"XLFMSG")
I $D(MSG) Q 0
;Build the message array
S NBLOCKS=0,(FNUM,TEMP)=""
F S FNUM=$O(^TMP($J,"XLFDIQ",FNUM)) Q:FNUM="" D
. S IENS=""
. F S IENS=$O(^TMP($J,"XLFDIQ",FNUM,IENS)) Q:IENS="" D
.. S FIELDNUM=""
.. F S FIELDNUM=$O(^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM)) Q:FIELDNUM="" D
... S TEXT(0)=$G(^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM))
... S TEXT("E")=$G(^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM,"E"))
... S TEXT("I")=$G(^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM,"I"))
... F JND=0,"E","I" D
.... I TEXT(JND)="" Q
.... S TEXT=TEXT(JND)
....;Do not include the word-processing field indicator.
.... I TEXT'[WPI D
..... F IND=1:1:$L(TEXT) D
...... S TEMP=TEMP_$E(TEXT,IND)
...... I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
.... I TEXT[WPI D
..... S NL=0
..... F S NL=+$O(^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM,NL)) Q:NL=0 D
...... I WPZN S TEXT=^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM,NL,0)
...... E S TEXT=^TMP($J,"XLFDIQ",FNUM,IENS,FIELDNUM,NL)
...... F IND=1:1:$L(TEXT) D
....... S TEMP=TEMP_$E(TEXT,IND)
....... I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP
K ^TMP($J,"XLFDIQ")
S HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
K ^TMP($J,"XLFMSG")
Q HASH
;
;=============================
GENAREF(HASHLEN,AREF,DATAONLY) ;Return an SHA hash for a general array. AREF
;is the starting array reference, for example ABC or ^TMP($J,"XX").
;IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
N DONE,HASH,IND,LEN,NBLOCKS,PROOT,ROOT,START,TEMP,TEXT
I AREF="" Q 0
S PROOT=$P(AREF,")",1)
S TEMP=$NA(@AREF)
S ROOT=$P(TEMP,")",1)
S AREF=$Q(@AREF)
I AREF'[ROOT Q 0
S TEMP=""
S (DONE,NBLOCKS)=0
F Q:(AREF="")!(DONE) D
. S START=$F(AREF,ROOT)
. I DATAONLY S TEXT=@AREF
. E S LEN=$L(AREF),IND=$E(AREF,START,LEN),TEXT=PROOT_IND_"="_@AREF
. F IND=1:1:$L(TEXT) D
.. S TEMP=TEMP_$E(TEXT,IND)
.. I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
. S AREF=$Q(@AREF)
. I AREF'[ROOT S DONE=1
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP
S HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
K ^TMP($J,"XLFMSG")
Q HASH
;
;=============================
GLOBAL(HASHLEN,FILENUM,DATAONLY) ;Return an SHA hash for a global. IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
N DONE,HASH,IND,NBLOCKS,ROOT,ROOTN,TEMP,TEXT
S ROOT=$$ROOT^DILFD(FILENUM)
I ROOT="" Q 0
S ROOTN=$TR(ROOT,",",")")
S TEMP=$L(ROOTN)
I $E(ROOTN,TEMP)="(" S ROOTN=$E(ROOTN,1,(TEMP-1))
K ^TMP($J,"XLFMSG")
S NBLOCKS=0,TEMP=""
S DONE=0
F Q:DONE D
. S ROOTN=$Q(@ROOTN)
. I (ROOTN="")!(ROOTN'[ROOT) S DONE=1 Q
. I DATAONLY S TEXT=@ROOTN
. E S TEXT=ROOTN_"="_@ROOTN
. F IND=1:1:$L(TEXT) D
.. S TEMP=TEMP_$E(TEXT,IND)
.. I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP
S HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
K ^TMP($J,"XLFMSG")
Q HASH
;
;=============================
HOSTFILE(HASHLEN,PATH,FILENAME) ;Return a SHA hash for a host file. IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
N GBLZISH,HASH,IND,LN,OVFLN,NBLOCKS,SUCCESS,TEMP,TEXT
K ^TMP($J,"HF")
S GBLZISH="^TMP($J,""HF"",1)"
S GBLZISH=$NA(@GBLZISH)
S SUCCESS=$$FTG^%ZISH(PATH,FILENAME,GBLZISH,3)
I 'SUCCESS Q 0
S (NBLOCKS,LN)=0,TEMP=""
F S LN=+$O(^TMP($J,"HF",LN)) Q:LN=0 D
. S TEXT=^TMP($J,"HF",LN)
. F IND=1:1:$L(TEXT) D
.. S TEMP=TEMP_$E(TEXT,IND)
.. I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
.;Check for overflow lines
. I '$D(^TMP($J,"HF",LN,"OVF")) Q
. S OVFLN=0
. F S OVFLN=+$O(^TMP($J,"HF",LN,"OVF",OVFLN)) Q:OVFLN=0 D
.. S TEXT=^TMP($J,"HF",LN,"OVF",OVFLN)
.. F IND=1:1:$L(TEXT) D
... S TEMP=TEMP_$E(TEXT,IND)
... I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP
K ^TMP($J,"HF")
S HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
K ^TMP($J,"XLFMSG")
Q HASH
;
;=============================
LSHAN(HASHLEN,MSUB,NBLOCKS) ;SHA hash for a message too long for a single
;string. Cache objects version. IA #6157
;The message is in ^TMP($J,MSUB,N) where N goes from 1 to NBLOCKS.
;
N CHAR,COHASH,HASH,IND,LOCATION,STATUS,STREAM
K ^TMP($J,"STREAM")
;Put the message into a stream global.
S LOCATION=$NA(^TMP($J,"STREAM"))
S STREAM=##class(%Stream.GlobalCharacter).%New(LOCATION)
S STREAM.LineTerminator=""
F IND=1:1:NBLOCKS S STATUS=STREAM.WriteLine(^TMP($J,"XLFMSG",IND))
S STATUS=STREAM.%Save()
S COHASH=$SYSTEM.Encryption.SHAHashStream(HASHLEN,STREAM)
;Convert the string to hex.
S HASH=""
F IND=1:1:$L(COHASH) D
. S CHAR=$A(COHASH,IND)
. S HASH=HASH_$$RJ^XLFSTR($$CNV^XLFUTL(CHAR,16),2,"0")
K ^TMP($J,"STREAM")
Q HASH
;
;=============================
;LSHAN(HASHLEN,MSUB,NBLOCKS) ;SHA hash for a message too long for a single
;;string. GT.M version contributed K.S. Bhaskar. IA #6157
;;
;;The message is in ^TMP($J,MSUB,N) where N goes from 1 to NBLOCKS.
;N IO,IND,SHA
;S IO=$IO
;;name of program for 160 bit hash is sha1sum; other names use actual
;;hash size
;S:HASHLEN=160 HASHLEN=1
;O "SHA":(SHELL="/bin/sh":COMMAND="sha"_HASHLEN_"sum":STREAM:NOWRAP)::"PIPE" U "SHA"
;F IND=1:1:NBLOCKS W ^TMP($J,MSUB,IND) S $X=0
;W /EOF R SHA
;U IO C "SHA"
;Q $ZCO($P(SHA," ",1),"U")
;
;=============================
OR(X,Y) ;Bitwise logical OR, 32 bits. IA #6157
Q $ZBOOLEAN(X,Y,7) ;Cache
;N BOR,IND,XO
;S XO=0
;F IND=1:1:32 S BOR=$S(((X#2)+(Y#2))>0:1,1:0),XO=(XO\2)+(BOR*2147483648),X=X\2,Y=Y\2
;Q XO
;
;=============================
ROUTINE(HASHLEN,ROUTINE) ;Return a SHA hash for a routine. IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
N DIF,HASH,IND,LN,NBLOCKS,RA,TEMP,X,XCNP
K ^TMP($J,"XLFMSG")
S XCNP=0
S DIF="RA("
S X=ROUTINE
;Make sure the routine exists.
X ^%ZOSF("TEST")
I '$T Q 0
X ^%ZOSF("LOAD")
S NBLOCKS=0,TEMP=""
F LN=1:1:(XCNP-1) D
. F IND=1:1:$L(RA(LN,0)) D
.. S TEMP=TEMP_$E(RA(LN,0),IND)
.. I $L(TEMP)=1024 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP,TEMP=""
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,"XLFMSG",NBLOCKS)=TEMP
S HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
K ^TMP($J,"XLFMSG")
Q HASH
;
;=============================
SHAN(HASHLEN,MESSAGE) ;SHA hash for a message that can be passed as a single
;string. IA #6157
I '$$CHASHLEN(HASHLEN) Q -1
;
N CHAR,COHASH,HASH,IND
S COHASH=$SYSTEM.Encryption.SHAHash(HASHLEN,MESSAGE)
;Convert the string to hex.
S HASH=""
F IND=1:1:$L(COHASH) D
. S CHAR=$A(COHASH,IND)
. S HASH=HASH_$$RJ^XLFSTR($$CNV^XLFUTL(CHAR,16),2,"0")
Q HASH
;
;=============================
;SHAN(HASHLEN,MESSAGE) ;SHA hash for a message that can be passed as a single
;;string. GT.M version contributed K.S. Bhaskar. IA #6157
;I '$$CHASHLEN(HASHLEN) Q -1
;S IO=$IO
;S:HASHLEN=160 HASHLEN=1 ; name of program for 160 bit hash is sha1sum
;;other names use actual hash size
;O "SHA":(SHELL="/bin/sh":COMMAND="sha"_HASHLEN_"sum":STREAM:NOWRAP)::"PIPE" U "SHA"
;W MESSAGE S $X=0 W /EOF R SHA
;U IO C "SHA"
;Q $ZCO($P(SHA," ",1),"U")
;;
;=============================
XOR(X,Y) ;Bitwise logical XOR, 32 bits. IA #6157
Q $ZBOOLEAN(X,Y,6) ;Cache
;N IND,XO
;S XO=0
;F IND=1:1:32 S XO=(XO\2)+(((X+Y)#2)*2147483648),X=X\2,Y=Y\2
;Q XO
;
;=============================
;Tests
;=============================
TESTS ;
N END,HASH,HASHLEN,IND,JND,LEN,LINE,MSG,NBLOCKS,REFHASH,REPS,START,STR
W !,"Starting the tests."
F IND=1:1 S LINE=$P($T(TESTVEC+IND),";;",2) Q:LINE=-1 D
. I LINE["msg" D
.. S STR=$P(LINE,":",2),REPS=$P(LINE,":",3)
.. S MSG=$S(STR="":"the null string",1:STR)
.. W !!!,"The message is: ",MSG
.. I REPS>1 W !,"Repeated ",REPS," times."
.. S LEN=$L(STR)*REPS
.. W !,"Its length is: ",LEN
.. D TMPLOAD("XLFMSG",1024,STR,REPS,.NBLOCKS)
. I LINE["hash" D
.. S HASHLEN=$P(LINE,":",2),REFHASH=$P(LINE,":",3)
.. W !!,"Hash length = ",HASHLEN
.. W !,"Hash is: ",REFHASH
.. S REFHASH=$TR(REFHASH," ","")
.. I LEN<32767 D
... S START=$$CPUTIME^XLFSHAN
... S HASH=$$SHAN^XLFSHAN(HASHLEN,STR)
... S END=$$CPUTIME^XLFSHAN
... I HASH=REFHASH W !,"SHAN test passed."
... E D
.... W !,"SHAN test failed.",!," Got: "
.... F JND=1:1:$L(HASH) W $E(HASH,JND) I (JND#8)=0 W " "
... W !," Elapsed time: ",$$ETIMEMS^XLFSHAN(START,END)
.. S START=$$CPUTIME^XLFSHAN
.. S HASH=$$LSHAN^XLFSHAN(HASHLEN,"XLFMSG",NBLOCKS)
.. S END=$$CPUTIME^XLFSHAN
.. I HASH=REFHASH W !,"LSHAN test passed."
.. E D
... W !,"LSHAN test failed.",!," Got: "
... F JND=1:1:$L(HASH) W $E(HASH,JND) I (JND#8)=0 W " "
.. W !," Elapsed time: ",$$ETIMEMS^XLFSHAN(START,END)
K ^TMP($J,"XLFMSG")
Q
;
;=============================
TMPLOAD(SUB,BLKSIZE,STR,REPS,NBLOCKS) ;Load the ^TMP global.
N STRLEN
K ^TMP($J,SUB)
S STRLEN=$L(STR)
S LEN=STRLEN*REPS
I LEN'>BLKSIZE S ^TMP($J,SUB,1)=STR,NBLOCKS=1 Q
N IND,JND,TEMP
S NBLOCKS=0,TEMP=""
F IND=1:1:REPS D
. F JND=1:1:STRLEN D
.. S TEMP=TEMP_$E(STR,JND)
.. I $L(TEMP)=BLKSIZE S NBLOCKS=NBLOCKS+1,^TMP($J,SUB,NBLOCKS)=TEMP,TEMP=""
I $L(TEMP)>0 S NBLOCKS=NBLOCKS+1,^TMP($J,SUB,NBLOCKS)=TEMP
Q
;
;=============================
;Test vectors from http://www.di-mgt.com.au/sha_testvectors.html
;Format is msg:message:reps
;Followed by hash:hash length:HASH
;-1 terminates the test vectors.
TESTVEC ;
;;msg::1
;;hash:160:DA39A3EE 5E6B4B0D 3255BFEF 95601890 AFD80709
;;hash:224:D14A028C 2A3A2BC9 476102BB 288234C4 15A2B01F 828EA62A C5B3E42F
;;hash:256:E3B0C442 98FC1C14 9AFBF4C8 996FB924 27AE41E4 649B934C A495991B 7852B855
;;hash:384:38B060A7 51AC9638 4CD9327E B1B1E36A 21FDB711 14BE0743 4C0CC7BF 63F6E1DA 274EDEBF E76F65FB D51AD2F1 4898B95B
;;hash:512:CF83E135 7EEFB8BD F1542850 D66D8007 D620E405 0B5715DC 83F4A921 D36CE9CE 47D0D13C 5D85F2B0 FF8318D2 877EEC2F 63B931BD 47417A81 A538327A F927DA3E
;;msg:abc:1
;;hash:160:A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
;;hash:224:23097D22 3405D822 8642A477 BDA255B3 2AADBCE4 BDA0B3F7 E36C9DA7
;;hash:256:BA7816BF 8F01CFEA 414140DE 5DAE2223 B00361A3 96177A9C B410FF61 F20015AD
;;hash:384:CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7
;;hash:512:DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F
;;msg:abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq:1
;;hash:160:84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
;;hash:224:75388B16 512776CC 5DBA5DA1 FD890150 B0C6455C B4F58B19 52522525
;;hash:256:248D6A61 D20638B8 E5C02693 0C3E6039 A33CE459 64FF2167 F6ECEDD4 19DB06C1
;;hash:384:3391FDDD FC8DC739 3707A65B 1B470939 7CF8B1D1 62AF05AB FE8F450D E5F36BC6 B0455A85 20BC4E6F 5FE95B1F E3C8452B
;;hash:512:204A8FC6 DDA82F0A 0CED7BEB 8E08A416 57C16EF4 68B228A8 279BE331 A703C335 96FD15C1 3B1B07F9 AA1D3BEA 57789CA0 31AD85C7 A71DD703 54EC6312 38CA3445
;;msg:abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu:1
;;hash:160:A49B2446 A02C645B F419F995 B6709125 3A04A259
;;hash:224:C97CA9A5 59850CE9 7A04A96D EF6D99A9 E0E0E2AB 14E6B8DF 265FC0B3
;;hash:256:CF5B16A7 78AF8380 036CE59E 7B049237 0B249B11 E8F07A51 AFAC4503 7AFEE9D1
;;hash:384:09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039
;;hash:512:8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909
;;msg:a:1000000
;;hash:160:34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
;;hash:224:20794655 980C91D8 BBB4C1EA 97618A4B F03F4258 1948B2EE 4EE7AD67
;;hash:256:CDC76E5C 9914FB92 81A1C7E2 84D73E67 F1809A48 A497200E 046D39CC C7112CD0
;;hash:384:9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985
;;hash:512:E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B
;;-1
--- Routine Detail --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HXLFSHAN 13955 printed Oct 16, 2024@18:03:54 Page 2
XLFSHAN ;ISL/PKR SHA secure hash routines. ;09/30/2016
+1 ;;8.0;KERNEL;**657**;Jul 10, 1995;Build 9
+2 ;Per VA Directive 6402, this routine should not be modified.
+3 QUIT
+4 ;=============================
AND(X,Y) ;Bitwise logical AND, 32 bits. IA #6157
+1 ;Cache
QUIT $ZBOOLEAN(X,Y,1)
+2 ;N IND,XA
+3 ;S XA=0
+4 ;F IND=1:1:32 S XA=(XA\2)+((((X#2)+(Y#2))\2)*2147483648),X=X\2,Y=Y\2
+5 ;Q XA
+6 ;
+7 ;=============================
CHASHLEN(HASHLEN) ;Make sure the hash length is one of the acceptable
+1 ;values.
+2 IF HASHLEN=160
QUIT 1
+3 IF HASHLEN=224
QUIT 1
+4 IF HASHLEN=256
QUIT 1
+5 IF HASHLEN=384
QUIT 1
+6 IF HASHLEN=512
QUIT 1
+7 QUIT 0
+8 ;
+9 ;=============================
CPUTIME() ;Returns two comma-delimited pieces, "system" CPU time and "user"
+1 ;CPU time (except on VMS where no separate times are available).
+2 ;Time is returned as milliseconds of CPU time.
+3 QUIT $SYSTEM.Process.GetCPUTime()
+4 ;GT.M
+5 ;Q $ZGETJPI("","CPUTIM")*10
+6 ;
+7 ;=============================
ETIMEMS(START,END) ;Calculate and return the elapsed time in milliseconds.
+1 ;START and STOP times are set by calling $$CPUTIME.
+2 NEW ETIME,TEXT
+3 SET END=$PIECE(END,",",2)
+4 SET START=$PIECE(START,",",2)
+5 SET ETIME=END-START
+6 SET TEXT=ETIME_" milliseconds"
+7 QUIT TEXT
+8 ;
+9 ;=============================
FILE(HASHLEN,FILENUM,IEN,FIELD,FLAGS) ;Return a SHA hash for the specified
+1 ;file entry. IA #6157
+2 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+3 NEW IENS,IND,FIELDNUM,FNUM,HASH,MSG,NBLOCKS,NL,TARGET,TEMP,TEXT,WPI,WPZN
+4 KILL ^TMP($JOB,"XLFDIQ"),^TMP($JOB,"XLFMSG")
+5 SET TARGET=$NAME(^TMP($JOB,"XLFDIQ"))
+6 SET WPI=$PIECE(TARGET,")",1)
+7 SET FLAGS=$GET(FLAGS)
+8 SET WPZN=$SELECT(FLAGS["Z":1,1:0)
+9 IF $GET(FIELD)=""
SET FIELD="**"
+10 DO GETS^DIQ(FILENUM,IEN,FIELD,FLAGS,TARGET,"XLFMSG")
+11 IF $DATA(MSG)
QUIT 0
+12 ;Build the message array
+13 SET NBLOCKS=0
SET (FNUM,TEMP)=""
+14 FOR
SET FNUM=$ORDER(^TMP($JOB,"XLFDIQ",FNUM))
if FNUM=""
QUIT
Begin DoDot:1
+15 SET IENS=""
+16 FOR
SET IENS=$ORDER(^TMP($JOB,"XLFDIQ",FNUM,IENS))
if IENS=""
QUIT
Begin DoDot:2
+17 SET FIELDNUM=""
+18 FOR
SET FIELDNUM=$ORDER(^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM))
if FIELDNUM=""
QUIT
Begin DoDot:3
+19 SET TEXT(0)=$GET(^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM))
+20 SET TEXT("E")=$GET(^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM,"E"))
+21 SET TEXT("I")=$GET(^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM,"I"))
+22 FOR JND=0,"E","I"
Begin DoDot:4
+23 IF TEXT(JND)=""
QUIT
+24 SET TEXT=TEXT(JND)
+25 ;Do not include the word-processing field indicator.
+26 IF TEXT'[WPI
Begin DoDot:5
+27 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:6
+28 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+29 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:6
End DoDot:5
+30 IF TEXT[WPI
Begin DoDot:5
+31 SET NL=0
+32 FOR
SET NL=+$ORDER(^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM,NL))
if NL=0
QUIT
Begin DoDot:6
+33 IF WPZN
SET TEXT=^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM,NL,0)
+34 IF '$TEST
SET TEXT=^TMP($JOB,"XLFDIQ",FNUM,IENS,FIELDNUM,NL)
+35 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:7
+36 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+37 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:7
End DoDot:6
End DoDot:5
End DoDot:4
End DoDot:3
End DoDot:2
End DoDot:1
+38 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
+39 KILL ^TMP($JOB,"XLFDIQ")
+40 SET HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+41 KILL ^TMP($JOB,"XLFMSG")
+42 QUIT HASH
+43 ;
+44 ;=============================
GENAREF(HASHLEN,AREF,DATAONLY) ;Return an SHA hash for a general array. AREF
+1 ;is the starting array reference, for example ABC or ^TMP($J,"XX").
+2 ;IA #6157
+3 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+4 NEW DONE,HASH,IND,LEN,NBLOCKS,PROOT,ROOT,START,TEMP,TEXT
+5 IF AREF=""
QUIT 0
+6 SET PROOT=$PIECE(AREF,")",1)
+7 SET TEMP=$NAME(@AREF)
+8 SET ROOT=$PIECE(TEMP,")",1)
+9 SET AREF=$QUERY(@AREF)
+10 IF AREF'[ROOT
QUIT 0
+11 SET TEMP=""
+12 SET (DONE,NBLOCKS)=0
+13 FOR
if (AREF="")!(DONE)
QUIT
Begin DoDot:1
+14 SET START=$FIND(AREF,ROOT)
+15 IF DATAONLY
SET TEXT=@AREF
+16 IF '$TEST
SET LEN=$LENGTH(AREF)
SET IND=$EXTRACT(AREF,START,LEN)
SET TEXT=PROOT_IND_"="_@AREF
+17 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:2
+18 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+19 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:2
+20 SET AREF=$QUERY(@AREF)
+21 IF AREF'[ROOT
SET DONE=1
End DoDot:1
+22 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
+23 SET HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+24 KILL ^TMP($JOB,"XLFMSG")
+25 QUIT HASH
+26 ;
+27 ;=============================
GLOBAL(HASHLEN,FILENUM,DATAONLY) ;Return an SHA hash for a global. IA #6157
+1 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+2 NEW DONE,HASH,IND,NBLOCKS,ROOT,ROOTN,TEMP,TEXT
+3 SET ROOT=$$ROOT^DILFD(FILENUM)
+4 IF ROOT=""
QUIT 0
+5 SET ROOTN=$TRANSLATE(ROOT,",",")")
+6 SET TEMP=$LENGTH(ROOTN)
+7 IF $EXTRACT(ROOTN,TEMP)="("
SET ROOTN=$EXTRACT(ROOTN,1,(TEMP-1))
+8 KILL ^TMP($JOB,"XLFMSG")
+9 SET NBLOCKS=0
SET TEMP=""
+10 SET DONE=0
+11 FOR
if DONE
QUIT
Begin DoDot:1
+12 SET ROOTN=$QUERY(@ROOTN)
+13 IF (ROOTN="")!(ROOTN'[ROOT)
SET DONE=1
QUIT
+14 IF DATAONLY
SET TEXT=@ROOTN
+15 IF '$TEST
SET TEXT=ROOTN_"="_@ROOTN
+16 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:2
+17 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+18 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:2
End DoDot:1
+19 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
+20 SET HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+21 KILL ^TMP($JOB,"XLFMSG")
+22 QUIT HASH
+23 ;
+24 ;=============================
HOSTFILE(HASHLEN,PATH,FILENAME) ;Return a SHA hash for a host file. IA #6157
+1 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+2 NEW GBLZISH,HASH,IND,LN,OVFLN,NBLOCKS,SUCCESS,TEMP,TEXT
+3 KILL ^TMP($JOB,"HF")
+4 SET GBLZISH="^TMP($J,""HF"",1)"
+5 SET GBLZISH=$NAME(@GBLZISH)
+6 SET SUCCESS=$$FTG^%ZISH(PATH,FILENAME,GBLZISH,3)
+7 IF 'SUCCESS
QUIT 0
+8 SET (NBLOCKS,LN)=0
SET TEMP=""
+9 FOR
SET LN=+$ORDER(^TMP($JOB,"HF",LN))
if LN=0
QUIT
Begin DoDot:1
+10 SET TEXT=^TMP($JOB,"HF",LN)
+11 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:2
+12 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+13 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:2
+14 ;Check for overflow lines
+15 IF '$DATA(^TMP($JOB,"HF",LN,"OVF"))
QUIT
+16 SET OVFLN=0
+17 FOR
SET OVFLN=+$ORDER(^TMP($JOB,"HF",LN,"OVF",OVFLN))
if OVFLN=0
QUIT
Begin DoDot:2
+18 SET TEXT=^TMP($JOB,"HF",LN,"OVF",OVFLN)
+19 FOR IND=1:1:$LENGTH(TEXT)
Begin DoDot:3
+20 SET TEMP=TEMP_$EXTRACT(TEXT,IND)
+21 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:3
End DoDot:2
End DoDot:1
+22 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
+23 KILL ^TMP($JOB,"HF")
+24 SET HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+25 KILL ^TMP($JOB,"XLFMSG")
+26 QUIT HASH
+27 ;
+28 ;=============================
LSHAN(HASHLEN,MSUB,NBLOCKS) ;SHA hash for a message too long for a single
+1 ;string. Cache objects version. IA #6157
+2 ;The message is in ^TMP($J,MSUB,N) where N goes from 1 to NBLOCKS.
+3 ;
+4 NEW CHAR,COHASH,HASH,IND,LOCATION,STATUS,STREAM
+5 KILL ^TMP($JOB,"STREAM")
+6 ;Put the message into a stream global.
+7 SET LOCATION=$NAME(^TMP($JOB,"STREAM"))
+8 SET STREAM=##class(%Stream.GlobalCharacter).%New(LOCATION)
+9 SET STREAM.LineTerminator=""
+10 FOR IND=1:1:NBLOCKS
SET STATUS=STREAM.WriteLine(^TMP($JOB,"XLFMSG",IND))
+11 SET STATUS=STREAM.%Save()
+12 SET COHASH=$SYSTEM.Encryption.SHAHashStream(HASHLEN,STREAM)
+13 ;Convert the string to hex.
+14 SET HASH=""
+15 FOR IND=1:1:$LENGTH(COHASH)
Begin DoDot:1
+16 SET CHAR=$ASCII(COHASH,IND)
+17 SET HASH=HASH_$$RJ^XLFSTR($$CNV^XLFUTL(CHAR,16),2,"0")
End DoDot:1
+18 KILL ^TMP($JOB,"STREAM")
+19 QUIT HASH
+20 ;
+21 ;=============================
+22 ;LSHAN(HASHLEN,MSUB,NBLOCKS) ;SHA hash for a message too long for a single
+23 ;;string. GT.M version contributed K.S. Bhaskar. IA #6157
+24 ;;
+25 ;;The message is in ^TMP($J,MSUB,N) where N goes from 1 to NBLOCKS.
+26 ;N IO,IND,SHA
+27 ;S IO=$IO
+28 ;;name of program for 160 bit hash is sha1sum; other names use actual
+29 ;;hash size
+30 ;S:HASHLEN=160 HASHLEN=1
+31 ;O "SHA":(SHELL="/bin/sh":COMMAND="sha"_HASHLEN_"sum":STREAM:NOWRAP)::"PIPE" U "SHA"
+32 ;F IND=1:1:NBLOCKS W ^TMP($J,MSUB,IND) S $X=0
+33 ;W /EOF R SHA
+34 ;U IO C "SHA"
+35 ;Q $ZCO($P(SHA," ",1),"U")
+36 ;
+37 ;=============================
OR(X,Y) ;Bitwise logical OR, 32 bits. IA #6157
+1 ;Cache
QUIT $ZBOOLEAN(X,Y,7)
+2 ;N BOR,IND,XO
+3 ;S XO=0
+4 ;F IND=1:1:32 S BOR=$S(((X#2)+(Y#2))>0:1,1:0),XO=(XO\2)+(BOR*2147483648),X=X\2,Y=Y\2
+5 ;Q XO
+6 ;
+7 ;=============================
ROUTINE(HASHLEN,ROUTINE) ;Return a SHA hash for a routine. IA #6157
+1 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+2 NEW DIF,HASH,IND,LN,NBLOCKS,RA,TEMP,X,XCNP
+3 KILL ^TMP($JOB,"XLFMSG")
+4 SET XCNP=0
+5 SET DIF="RA("
+6 SET X=ROUTINE
+7 ;Make sure the routine exists.
+8 XECUTE ^%ZOSF("TEST")
+9 IF '$TEST
QUIT 0
+10 XECUTE ^%ZOSF("LOAD")
+11 SET NBLOCKS=0
SET TEMP=""
+12 FOR LN=1:1:(XCNP-1)
Begin DoDot:1
+13 FOR IND=1:1:$LENGTH(RA(LN,0))
Begin DoDot:2
+14 SET TEMP=TEMP_$EXTRACT(RA(LN,0),IND)
+15 IF $LENGTH(TEMP)=1024
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
SET TEMP=""
End DoDot:2
End DoDot:1
+16 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,"XLFMSG",NBLOCKS)=TEMP
+17 SET HASH=$$LSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+18 KILL ^TMP($JOB,"XLFMSG")
+19 QUIT HASH
+20 ;
+21 ;=============================
SHAN(HASHLEN,MESSAGE) ;SHA hash for a message that can be passed as a single
+1 ;string. IA #6157
+2 IF '$$CHASHLEN(HASHLEN)
QUIT -1
+3 ;
+4 NEW CHAR,COHASH,HASH,IND
+5 SET COHASH=$SYSTEM.Encryption.SHAHash(HASHLEN,MESSAGE)
+6 ;Convert the string to hex.
+7 SET HASH=""
+8 FOR IND=1:1:$LENGTH(COHASH)
Begin DoDot:1
+9 SET CHAR=$ASCII(COHASH,IND)
+10 SET HASH=HASH_$$RJ^XLFSTR($$CNV^XLFUTL(CHAR,16),2,"0")
End DoDot:1
+11 QUIT HASH
+12 ;
+13 ;=============================
+14 ;SHAN(HASHLEN,MESSAGE) ;SHA hash for a message that can be passed as a single
+15 ;;string. GT.M version contributed K.S. Bhaskar. IA #6157
+16 ;I '$$CHASHLEN(HASHLEN) Q -1
+17 ;S IO=$IO
+18 ;S:HASHLEN=160 HASHLEN=1 ; name of program for 160 bit hash is sha1sum
+19 ;;other names use actual hash size
+20 ;O "SHA":(SHELL="/bin/sh":COMMAND="sha"_HASHLEN_"sum":STREAM:NOWRAP)::"PIPE" U "SHA"
+21 ;W MESSAGE S $X=0 W /EOF R SHA
+22 ;U IO C "SHA"
+23 ;Q $ZCO($P(SHA," ",1),"U")
+24 ;;
+25 ;=============================
XOR(X,Y) ;Bitwise logical XOR, 32 bits. IA #6157
+1 ;Cache
QUIT $ZBOOLEAN(X,Y,6)
+2 ;N IND,XO
+3 ;S XO=0
+4 ;F IND=1:1:32 S XO=(XO\2)+(((X+Y)#2)*2147483648),X=X\2,Y=Y\2
+5 ;Q XO
+6 ;
+7 ;=============================
+8 ;Tests
+9 ;=============================
TESTS ;
+1 NEW END,HASH,HASHLEN,IND,JND,LEN,LINE,MSG,NBLOCKS,REFHASH,REPS,START,STR
+2 WRITE !,"Starting the tests."
+3 FOR IND=1:1
SET LINE=$PIECE($TEXT(TESTVEC+IND),";;",2)
if LINE=-1
QUIT
Begin DoDot:1
+4 IF LINE["msg"
Begin DoDot:2
+5 SET STR=$PIECE(LINE,":",2)
SET REPS=$PIECE(LINE,":",3)
+6 SET MSG=$SELECT(STR="":"the null string",1:STR)
+7 WRITE !!!,"The message is: ",MSG
+8 IF REPS>1
WRITE !,"Repeated ",REPS," times."
+9 SET LEN=$LENGTH(STR)*REPS
+10 WRITE !,"Its length is: ",LEN
+11 DO TMPLOAD("XLFMSG",1024,STR,REPS,.NBLOCKS)
End DoDot:2
+12 IF LINE["hash"
Begin DoDot:2
+13 SET HASHLEN=$PIECE(LINE,":",2)
SET REFHASH=$PIECE(LINE,":",3)
+14 WRITE !!,"Hash length = ",HASHLEN
+15 WRITE !,"Hash is: ",REFHASH
+16 SET REFHASH=$TRANSLATE(REFHASH," ","")
+17 IF LEN<32767
Begin DoDot:3
+18 SET START=$$CPUTIME^XLFSHAN
+19 SET HASH=$$SHAN^XLFSHAN(HASHLEN,STR)
+20 SET END=$$CPUTIME^XLFSHAN
+21 IF HASH=REFHASH
WRITE !,"SHAN test passed."
+22 IF '$TEST
Begin DoDot:4
+23 WRITE !,"SHAN test failed.",!," Got: "
+24 FOR JND=1:1:$LENGTH(HASH)
WRITE $EXTRACT(HASH,JND)
IF (JND#8)=0
WRITE " "
End DoDot:4
+25 WRITE !," Elapsed time: ",$$ETIMEMS^XLFSHAN(START,END)
End DoDot:3
+26 SET START=$$CPUTIME^XLFSHAN
+27 SET HASH=$$LSHAN^XLFSHAN(HASHLEN,"XLFMSG",NBLOCKS)
+28 SET END=$$CPUTIME^XLFSHAN
+29 IF HASH=REFHASH
WRITE !,"LSHAN test passed."
+30 IF '$TEST
Begin DoDot:3
+31 WRITE !,"LSHAN test failed.",!," Got: "
+32 FOR JND=1:1:$LENGTH(HASH)
WRITE $EXTRACT(HASH,JND)
IF (JND#8)=0
WRITE " "
End DoDot:3
+33 WRITE !," Elapsed time: ",$$ETIMEMS^XLFSHAN(START,END)
End DoDot:2
End DoDot:1
+34 KILL ^TMP($JOB,"XLFMSG")
+35 QUIT
+36 ;
+37 ;=============================
TMPLOAD(SUB,BLKSIZE,STR,REPS,NBLOCKS) ;Load the ^TMP global.
+1 NEW STRLEN
+2 KILL ^TMP($JOB,SUB)
+3 SET STRLEN=$LENGTH(STR)
+4 SET LEN=STRLEN*REPS
+5 IF LEN'>BLKSIZE
SET ^TMP($JOB,SUB,1)=STR
SET NBLOCKS=1
QUIT
+6 NEW IND,JND,TEMP
+7 SET NBLOCKS=0
SET TEMP=""
+8 FOR IND=1:1:REPS
Begin DoDot:1
+9 FOR JND=1:1:STRLEN
Begin DoDot:2
+10 SET TEMP=TEMP_$EXTRACT(STR,JND)
+11 IF $LENGTH(TEMP)=BLKSIZE
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,SUB,NBLOCKS)=TEMP
SET TEMP=""
End DoDot:2
End DoDot:1
+12 IF $LENGTH(TEMP)>0
SET NBLOCKS=NBLOCKS+1
SET ^TMP($JOB,SUB,NBLOCKS)=TEMP
+13 QUIT
+14 ;
+15 ;=============================
+16 ;Test vectors from http://www.di-mgt.com.au/sha_testvectors.html
+17 ;Format is msg:message:reps
+18 ;Followed by hash:hash length:HASH
+19 ;-1 terminates the test vectors.
TESTVEC ;
+1 ;;msg::1
+2 ;;hash:160:DA39A3EE 5E6B4B0D 3255BFEF 95601890 AFD80709
+3 ;;hash:224:D14A028C 2A3A2BC9 476102BB 288234C4 15A2B01F 828EA62A C5B3E42F
+4 ;;hash:256:E3B0C442 98FC1C14 9AFBF4C8 996FB924 27AE41E4 649B934C A495991B 7852B855
+5 ;;hash:384:38B060A7 51AC9638 4CD9327E B1B1E36A 21FDB711 14BE0743 4C0CC7BF 63F6E1DA 274EDEBF E76F65FB D51AD2F1 4898B95B
+6 ;;hash:512:CF83E135 7EEFB8BD F1542850 D66D8007 D620E405 0B5715DC 83F4A921 D36CE9CE 47D0D13C 5D85F2B0 FF8318D2 877EEC2F 63B931BD 47417A81 A538327A F927DA3E
+7 ;;msg:abc:1
+8 ;;hash:160:A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+9 ;;hash:224:23097D22 3405D822 8642A477 BDA255B3 2AADBCE4 BDA0B3F7 E36C9DA7
+10 ;;hash:256:BA7816BF 8F01CFEA 414140DE 5DAE2223 B00361A3 96177A9C B410FF61 F20015AD
+11 ;;hash:384:CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7
+12 ;;hash:512:DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F
+13 ;;msg:abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq:1
+14 ;;hash:160:84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+15 ;;hash:224:75388B16 512776CC 5DBA5DA1 FD890150 B0C6455C B4F58B19 52522525
+16 ;;hash:256:248D6A61 D20638B8 E5C02693 0C3E6039 A33CE459 64FF2167 F6ECEDD4 19DB06C1
+17 ;;hash:384:3391FDDD FC8DC739 3707A65B 1B470939 7CF8B1D1 62AF05AB FE8F450D E5F36BC6 B0455A85 20BC4E6F 5FE95B1F E3C8452B
+18 ;;hash:512:204A8FC6 DDA82F0A 0CED7BEB 8E08A416 57C16EF4 68B228A8 279BE331 A703C335 96FD15C1 3B1B07F9 AA1D3BEA 57789CA0 31AD85C7 A71DD703 54EC6312 38CA3445
+19 ;;msg:abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu:1
+20 ;;hash:160:A49B2446 A02C645B F419F995 B6709125 3A04A259
+21 ;;hash:224:C97CA9A5 59850CE9 7A04A96D EF6D99A9 E0E0E2AB 14E6B8DF 265FC0B3
+22 ;;hash:256:CF5B16A7 78AF8380 036CE59E 7B049237 0B249B11 E8F07A51 AFAC4503 7AFEE9D1
+23 ;;hash:384:09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039
+24 ;;hash:512:8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909
+25 ;;msg:a:1000000
+26 ;;hash:160:34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+27 ;;hash:224:20794655 980C91D8 BBB4C1EA 97618A4B F03F4258 1948B2EE 4EE7AD67
+28 ;;hash:256:CDC76E5C 9914FB92 81A1C7E2 84D73E67 F1809A48 A497200E 046D39CC C7112CD0
+29 ;;hash:384:9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985
+30 ;;hash:512:E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B
+31 ;;-1