class Crypt extends Object
Hashes values and files, encrypts and decrypts with AES, derives keys from passwords, and returns cryptographically secure random values. Every method is called on the class itself.
The class is exported by the KS module:
#Import "Ks" { Crypt }
Returns the digest of a value, using any supported algorithm.
Digest := Crypt.Hash(Value , Algorithm := "SHA256", Encoding := "UTF-8")
Type: String, StringBuffer, Buffer or File
The data to hash. See Input Values and Text Encoding.
Type: String
If omitted, it defaults to SHA256. Otherwise specify MD5, SHA1, SHA256, SHA384, SHA512 or CRC32. The name is not case-sensitive and may contain hyphens, as in SHA-256.
Type: String
The encoding a String or StringBuffer Value is converted to before hashing, named as for A_FileEncoding. If omitted, it defaults to UTF-8. It has no effect on binary inputs.
Type: String
The digest as uppercase hexadecimal. See Digest Format.
Security warning: MD5 and SHA-1 are unsuitable for collision-resistant security uses. Use SHA-256 or stronger unless compatibility requires an older digest.
A ValueError is thrown if Algorithm is not one of the names listed above, or if Value is a File which is not open for reading. A TypeError is thrown if Value is a type which holds no bytes, such as a number.
Computes a keyed message authentication code.
Digest := Crypt.Hmac(Value, Key , Algorithm := "SHA256", Encoding := "UTF-8")
The message: a String, StringBuffer, Buffer or open File. Text encoding and File position rules are the same as for Hash.
The secret key: a String, StringBuffer or Buffer. Strings use Encoding; a Buffer retains its bytes. A File cannot serve as the key.
SHA1, SHA256 (the default), SHA384 or SHA512, named as for Hash.
The encoding for both textual inputs, defaulting to UTF-8. Names are accepted as for FileEncoding.
Returns a String containing uppercase hexadecimal, as Hash does.
An unsupported algorithm or encoding raises ValueError. An input which holds no bytes raises TypeError. A closed or write-only File raises ValueError. File read failures raise OSError.
Returns the digest of a file, read as a stream.
Digest := Crypt.HashFile(Path , Algorithm := "SHA256")
Type: String
The name of the file, which is assumed to be in A_WorkingDir if an absolute path is not specified.
Type: String
As for Hash.
Type: String
The digest as uppercase hexadecimal.
A ValueError is thrown if Path is empty or Algorithm is not recognized. An OSError is thrown if the file cannot be opened or read, and A_LastError is set to the operating system's error code.
Returns the CRC32 checksum of a value as an integer.
Checksum := Crypt.CRC32(Value , Encoding := "UTF-8")
CRC32 detects accidental corruption; it is not a cryptographic integrity check.
Crypt.Hash(Value, "CRC32") computes the same checksum but returns it as hexadecimal.
Encrypt encrypts data with a symmetric cipher; Decrypt reverses it.
Data := Crypt.Encrypt(Value, Key , Algorithm := "AES", Mode := "CBC", IV, Encoding := "UTF-8") Data := Crypt.Decrypt(Value, Key , Algorithm := "AES", Mode := "CBC", IV, Encoding := "UTF-8")
Both return a Buffer. Algorithm is AES, the only supported cipher. Mode is the chaining mode: CBC (the default), ECB, which encrypts each block independently and so reveals where the plaintext repeats, or CFB, which uses 8-bit feedback (CFB8). Decrypting requires the same algorithm, mode, key and encoding the data was encrypted under; a wrong key, a truncated input or a mismatched mode throws a ValueError.
GCM authenticates as well as encrypts: decrypting a message which has been altered throws a ValueError. A 16-byte authentication tag is appended to the result.
A String Value or Key is converted using Encoding, so reading decrypted text back requires StrGet with the same one.
The initialization vector (the nonce, under GCM) is not secret, but must differ for each message encrypted under the same key.
With IV omitted, each call draws a random vector, uses it, and writes it in front of the result, where Decrypt reads it back. Encrypting the same text twice therefore returns different data.
Supply IV — 16 bytes for a chaining mode, 12 for GCM, as RandomBytes returns them — only to match a format defined elsewhere. It is then used exactly as given and is not written to the result, so Decrypt must be handed the same vector back. A vector of the wrong length, or any vector at all with ECB, which uses none, throws a ValueError. A String vector is converted with Encoding.
Security warning: the key is used as it stands, padded to the algorithm's key size rather than stretched by a key-derivation function, so a passphrase is only as strong as its own entropy. Derive a key with PBKDF2 rather than passing a passphrase straight to Key.
Security warning: under a chaining mode — CBC, ECB or CFB — the result carries no authentication tag, so a ciphertext altered after the fact decrypts to rubbish instead of being detected. Use GCM for anything that crosses a boundary where someone could change it.
Derives key material from a password.
Key := Crypt.PBKDF2(Password, Salt , Iterations := 600000, Length := 32, Algorithm := "SHA256", Encoding := "UTF-8")
Returns Length bytes as a Buffer. Use it to derive a Key for Encrypt from a passphrase.
Salt need not be secret, but must differ per password, and the same salt is needed to derive the key again. RandomBytes produces one.
Algorithm is SHA1, SHA256 (the default), SHA384 or SHA512. A ValueError is thrown for any other name, for an iteration count below 1, or for a non-positive length.
Higher Iterations make both guessing the password and deriving the key slower; lower the default only to match a format defined elsewhere.
Returns cryptographically secure random bytes.
Data := Crypt.RandomBytes(Count)
Returns Count bytes as a Buffer, drawn from the same generator as SecureRandom.
Returns a cryptographically secure random number.
Value := Crypt.SecureRandom(Min, Max)
If both bounds are integers, the result is an integer; if either is floating-point, the result uses floating-point bounds. The range includes Max. If both are omitted, the result is an integer from -2147483648 to 2147483647.
For non-security uses where speed is preferred, use Random.
A String, or a StringBuffer taken as its text, is converted to bytes with Encoding, which defaults to UTF-8. An Encoding which cannot be resolved throws a ValueError.
A Buffer is hashed exactly as it stands, so no encoding applies to it.
An open File passed to any of the hashing methods has its whole content read as a stream, from the beginning of the file, and is left at the position it was on. Pending writes are flushed first. A stream which cannot seek is read from its current position instead, and a File which is closed or was opened write-only throws a ValueError. Encrypt and Decrypt do not accept a File.
A digest is returned as uppercase hexadecimal with no separators. Hex.Decode converts it to a Buffer of raw bytes. Compare digests case-insensitively, such as with =, since published checksums are often lowercase.
Hashes text, and matches what any other tool reports for it.
#Import "Ks" { Crypt }
MsgBox Crypt.Hash("abc", "SHA256") ; BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD
MsgBox Crypt.Hash("abc", "MD5") ; 900150983CD24FB0D6963F7D28E17F72
Verifies a download against a published checksum, comparing case-insensitively.
#Import "Ks" { Crypt }
Expected := "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
if (Crypt.HashFile(A_ScriptDir "\download.zip") = Expected)
MsgBox "Checksum matches."
else
MsgBox "Checksum does NOT match."
Encrypts text and reads it back.
#Import "Ks" { Crypt }
Secret := Crypt.Encrypt("hello", "my key")
Plain := Crypt.Decrypt(Secret, "my key")
MsgBox StrGet(Plain, Plain.Size, "UTF-8") ; hello
; The same text encrypts differently every time, because each call draws its own vector.
MsgBox Crypt.Encrypt("hello", "my key").Size ; 32: a 16-byte vector plus one 16-byte block
Computes an eight-digit TOTP from a Base32 secret with the 30-second step in RFC 6238. This example uses the RFC's public test secret; UnixTime is seconds since 1970-01-01 UTC.
#Import Ks { Crypt, Base32, Hex }
Totp(Secret, UnixTime, Algorithm := "SHA1") {
counter := Buffer(8), steps := UnixTime // 30
Loop 8
NumPut("UChar", (steps >> ((8 - A_Index) * 8)) & 255, counter, A_Index - 1)
digest := Hex.Decode(Crypt.Hmac(counter, Base32.Decode(Secret), Algorithm))
offset := NumGet(digest, digest.Size - 1, "UChar") & 15, number := 0
Loop 4
number := (number << 8) | NumGet(digest, offset + A_Index - 1, "UChar")
return Format("{1:08d}", Mod(number & 0x7fffffff, 100000000))
}
FileAppend Totp("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 59), "*" ; 94287082
Buffer, File, FileRead, Random, Base32, Base64, Hex, KS module