AbtMD5Engine printableDigest: generates Uppercase

26 views
Skip to first unread message

Joachim Tuchel

unread,
Jan 13, 2026, 5:21:48 AMJan 13
to VAST Community Forum
Hi there,

I am in need of a checksum algo to secure File uploads against data loss. So I thought I'll use TSTTCPW and give AbtMD5Engine a test drive.

So a snippet like this is all that's needed to create the MD checksum of a file on disk:

| byteArray file hash |

file := CfsReadFileStream open: 'myFile.txt.
byteArray := file contents asByteArray.
file close.

hash := (AbtMD5Engine printableDigest: byteArray).

Works fine, although extremely slow in comparison with the md5sum utility on Linux ( I suspect the reason is more the file reading part than MD5 Hashing - which is not relevant in my target scenario).
Interestingly, it produces a hash containing UPPERCASE characters, while md5sum and the spark-md5 js-Library create a lower case hash.

While it's not actually a big problem to convert the produced end expected hash to lowercase and compare them, but I wonder if this is correct behavior in VAST. I couldn't find any word on whether an MD5 hash has to be lower- or uppercase on Wkipedia, andMistral tells me MD5 hashes aren't case sensitive, so converting both to lower or uppercase before comparing is best practice. Sounds reasonable, because 5f results in the same hex number as 5F, so both strings represent the same hex number(s).

I wonder if people convert the two hashes to 
  1. an array of hex numbers (which  results in the same output for both lower and uppercase) 
  2. one very large number from the hex digits
  3. two lower- or uppercase Strings 
and compare these or just the string. While the result is always the same, I wonder if there is some best practie and any idea on why any of these is better than the other (I would guess the large hex number is probably slowest or memory inefficient?)

Am I wondering about something completely irrelevant (wouldn't really be surprised)?

Joachim

 
 




Seth Berman

unread,
Jan 13, 2026, 7:11:43 AMJan 13
to VAST Community Forum
Hi Joachim,

Do you have the crypto feature loaded? (IOW, are you using OpenSSL?)
If so, after you get the byte array from the file, then you can use:
(OSSslDigest md5 digest: byteArray) asHexString: false

- Seth 

Richard Sargent

unread,
Jan 14, 2026, 12:48:51 PMJan 14
to VAST Community Forum
Joachim,

I generate hashes for GBS files when I build a release. I run openssl todo so.

Pasting the source of two methods. One generates a specific hash for the release and the other drives it to generate three different hashses.
Example directory listing:
-rw-r----- 1 rsargent 1049089 4533116 Sep 18  2023 GemBuilder5.4.7.zip
-rw-r----- 1 rsargent 1049089      55 Sep 18  2023 GemBuilder5.4.7.zip.md5
-rw-r----- 1 rsargent 1049089      63 Sep 18  2023 GemBuilder5.4.7.zip.sha1
-rw-r----- 1 rsargent 1049089      87 Sep 18  2023 GemBuilder5.4.7.zip.sha256



!GbsBuild publicMethods !

generate: hashName digestForProductFileNamed: zipFileName
"Generate e.g. the MD5 or SHA-1, etc. digest for the product zip file."

| fileName rc outputString errorString |
fileName := zipFileName.
rc := GbxExternalProcess
execute: 'openssl'
arguments: (Array with: hashName with: '-r' with: '-out' with: fileName, '.', hashName with: fileName)
do:  [:outStream | "We don't care. We're sending the hash to the correct file." outputString := outStream contents]
errorStreamDo:
[:errorStream |
errorString := errorStream contents.
errorString isEmpty ifFalse: [self error: 'OpenSSL ', hashName, ' digest failed: ' , errorString]].
rc ~= 0
ifTrue: [self error: 'OpenSSL bad return code: ', rc printString, ' (', ((outputString printString, '/', errorString printString) copyReplaceAll: LineDelimiter with: ''), ')'].
!

generateHashesForProductFileNamed: zipFileName
"Generate the MD5, SHA1, and SHA256 hashes for the product zip file."

| currentWorkingDirectory |
currentWorkingDirectory := CfsDirectoryDescriptor getcwd.
CfsDirectoryDescriptor chdir: productDir asString.
[
#(md5 sha1 sha256)
do: [:eachHashName | self generate: eachHashName digestForProductFileNamed: zipFileName].
] ensure: [CfsDirectoryDescriptor chdir: currentWorkingDirectory]! !
Reply all
Reply to author
Forward
0 new messages