For Crypto, Code Less, Compile Quicker and Execute Faster

The new scripted languages such as Python and Node.js are convenient. But, unfortunately, they can be slow as they are scripted, and not…

Photo by Mauro Sbicego on Unsplash

For Crypto, Code Less, Compile Quicker and Execute Faster

The new scripted languages such as Python and Node.js are convenient. But, unfortunately, they can be slow as they are scripted, and not compiled. Each time the scripted code is run, the scripting engine must then convert each line of code to the required machine level code. This makes the code much slower than compiled languages, and also less robust.

Thus many applications in cryptography are written in C and C++, as they allow for fast execution and give low level access. Unfortunately it can be complex to compile programs, as we often need to install binary libraries and then link these in. The Go programming language, though, has a similar code syntax to C/C++, but is small and efficient and allows access to low-level functions, such as as pointers.

Go thus aims to “Code less, compile quicker, execute faster”.

So let’s use Go to implement some hashing functions, and implement compiled code for cryptography. An outline of the Go code is [here]:

package main
import (
"crypto/rand"
"golang.org/x/crypto/md4"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"golang.org/x/crypto/ripemd160"
"golang.org/x/crypto/sha3"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/scrypt"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/bcrypt"
"fmt"
"flag"
)
type params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
func generateRandomBytes(n uint32) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func main() {
s := "abc"
flag.Parse()
args := flag.Args()
s=args[0]
h1 := md4.New()
h2 := md5.Sum([]byte(s))
h3 := sha1.Sum([]byte(s))
h4 := sha256.Sum256([]byte(s))
h5 := sha512.Sum512([]byte(s))
h6 := ripemd160.New()
h7 := sha3.Sum256([]byte(s))
h8 := sha3.Sum512([]byte(s))
h9 := blake2b.Sum256([]byte(s))
h10 := blake2b.Sum512([]byte(s))
p := &params{
memory: 64 * 1024,
iterations: 1,
parallelism: 1,
saltLength: 16,
keyLength: 32,
}
salt, err := generateRandomBytes(p.saltLength)
h11 := argon2.IDKey([]byte(s), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
// Values are password, salt, N, r, p, key length
h12, err := scrypt.Key([]byte(s), salt, 1<<15, 4, 1, 32)
cost:=1
h13,err:=bcrypt.GenerateFromPassword([]byte(s), cost)
h1.Write([]byte(s))
h6.Write([]byte(s))
fmt.Println("Input: ",s)
fmt.Printf("MD4: %x\n", h1.Sum(nil))
fmt.Printf("MD5: %x\n", h2)
fmt.Printf("SHA-1: %x\n", h3)
fmt.Printf("SHA-256: %x\n", h4)
fmt.Printf("SHA-512: %x\n", h5)
fmt.Printf("RIPEMD160: %x\n", h6.Sum(nil))
fmt.Printf("SHA-3 256: %x\n", h7)
fmt.Printf("SHA-3 512: %x\n", h8)
fmt.Printf("Blake2b 256-bit: %x\n", h9)
fmt.Printf("Blake2b 512-bit: %x\n", h10)
if (err==nil) {
fmt.Printf("Argon2: %x\n", h11)
fmt.Printf("Scrypt: %x\n", h12)
fmt.Printf("BCrypt: %s\n", h13)
}
}

In this case we integrate cryptography libraries using the Import() statement. These are imported in the src folder using Git with:

go get -u golang.org/x/crypto/...

The great advantage with Go is that it can be installed in most operating systems, and then can be compiled into an executable version [install]. We first create this code as file called “hash.go” and then compile with:

go build hash.go

In Microsoft Windows, this then creates an executable file named “hash.exe”, and which can be run as a stand-alone program, and pass in an argument. A sample run is:

Input:  abc
MD4: a448017aaf21d8525fc10ae87aa6729d
MD5: 900150983cd24fb0d6963f7d28e17f72
SHA-1: a9993e364706816aba3e25717850c26c9cd0d89d
SHA-256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
SHA-512: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
RIPEMD160: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
SHA-3 256: 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532
SHA-3 512: b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0
Blake2b 256-bit: bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319
Blake2b 512-bit: ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923
Argon2: 685f42142b82c76041656f230ae7363e9b194f75da370040926169ec427499a6
Scrypt: 3fd40e6d8f98986a096b89809c30895417c78d7fad66c06fcda1366dbaec131f
BCrypt: $2a$10$xvdP8jgbUwSGlKwCgprIZ.9BtbyB6AGtQQ8sfL1c391L0Jot/MaJ.

We can also run this from the Go file with:

c:\godir> go run hash.go fred
Input: fred
MD4: d6b5275b4f929f0a92fed52597d29b1d
MD5: 570a90bfbf8c7eab5dc5d4e26832d5b1
SHA-1: 31017a722665e4afce586950f42944a6d331dabf
SHA-256: d0cfc2e5319b82cdc71a33873e826c93d7ee11363f8ac91c4fa3a2cfcd2286e5
SHA-512: 3566c33c35c59ba2587bac2a81526cf33ea0928111ed9e1616aa43fcffbc3f5d07e058c
80898cd286095b7587ad5edd3511fd943fd7d7743b1ded724262026f3
RIPEMD160: d518c29118fca3f5fbafd9efa17db154930fcced
SHA-3 256: 901e5b95a7c6f4c25f1dbb31931585a1aac6cac21eb1f09a39411f5ba4e710d6
SHA-3 512: 9d15efc1b71e0143a4daad34d5bb2e97d4968d80269e49c633aac69cc13d990b25295
685eacb5b29eb584a1f6dd92a8e91e257c0c493a869310bee0b8a2ef440
Blake2b 256-bit: 3e5f32e0066871d68a6713be8274fee3a079971d0ceaa44878f58beb0936a33
9
Blake2b 512-bit: 817bdde172952d439c9ccb1a4d91476c93cd4578038715f139d9095a9f7a180
26463d67e3c666733a8e4e733195414e7888631057b3857418f51a61848467d10
Argon2: 0bbde4e32ced1fc444a392ebd2888c42e0cd4fd8610bf2acb9323f13ce29b1c5
Scrypt: dc87fe00fb543f327ba44aaa579bbde6d94e2b33c151339b001e91067d3b6927
BCrypt: $2a$10$Uqe7dk52iIJDRmGAnSCXy.ejaPyyhsPqmek8dwrvh4DSedhCNEnmi

Conclusions

Want the advantages of scripted language, but the speed of C? Go is perhaps the answer. Here is the demo: