Skip to content

Instantly share code, notes, and snippets.

@abarisani
Last active April 6, 2019 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abarisani/c5af4b2b72875b61e15c0eefc4e6633d to your computer and use it in GitHub Desktop.
Save abarisani/c5af4b2b72875b61e15c0eefc4e6633d to your computer and use it in GitHub Desktop.
Golang userspace example for Linux Crypto API symmetric cipher
// Golang userspace example for Linux Crypto API symmetric cipher
//
// Copyright (c) F-Secure Corporation
//
// Andrea Barisani
// andrea.barisani@f-secure.com | andrea@inversepath.com
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation under version 3 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
//+build linux
package main
import (
"bytes"
"crypto/aes"
"encoding/hex"
"fmt"
"log"
"os"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
// NIST AES-128-CBC test vector
const KEY = "2b7e151628aed2a6abf7158809cf4f3c"
const IV = "000102030405060708090a0b0c0d0e0f"
const TV = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
const TC = "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2"
type af_alg_iv struct {
ivlen uint32
iv [aes.BlockSize]byte
}
func init() {
log.SetFlags(0)
log.SetOutput(os.Stdout)
}
func main() {
key, _ := hex.DecodeString(KEY)
iv, _ := hex.DecodeString(IV)
tv, _ := hex.DecodeString(TV)
tc, _ := hex.DecodeString(TC)
fd, err := unix.Socket(unix.AF_ALG, unix.SOCK_SEQPACKET, 0)
defer func() {
if err != nil {
log.Fatalf("error, %v", err)
}
}()
if err != nil {
return
}
defer unix.Close(fd)
addr := &unix.SockaddrALG{
Type: "skcipher",
Name: "cbc(aes)",
}
err = unix.Bind(fd, addr)
if err != nil {
return
}
err = syscall.SetsockoptString(fd, unix.SOL_ALG, unix.ALG_SET_KEY, string(key))
if err != nil {
return
}
apifd, _, _ := unix.Syscall(unix.SYS_ACCEPT, uintptr(fd), 0, 0)
fmt.Printf(" --------------------------------\n")
fmt.Printf(" NIST CBC-AES128.Encrypt example \n")
fmt.Printf(" --------------------------------\n")
fmt.Printf(" key: %x\n", key)
fmt.Printf(" iv: %x\n", iv)
fmt.Printf(" plaintext: %x\n", tv)
ciphertext, err := CryptoAPI(apifd, unix.ALG_OP_ENCRYPT, iv, tv)
if err != nil {
return
}
fmt.Printf("ciphertext: %x\n", ciphertext)
if !bytes.Equal(ciphertext, tc) {
err = fmt.Errorf("ciphertext mismatch, %x != %x", ciphertext, tc)
return
}
plaintext, err := CryptoAPI(apifd, unix.ALG_OP_DECRYPT, iv, tc)
if err != nil {
return
}
if !bytes.Equal(plaintext, tv) {
err = fmt.Errorf("plaintext mismatch, %x != %x", plaintext, tv)
return
}
}
func CryptoAPI(fd uintptr, mode uint32, iv []byte, input []byte) (output []byte, err error) {
api := os.NewFile(fd, "CryptoAPI")
cmsg := BuildCmsg(mode, iv)
output = make([]byte, len(input))
err = syscall.Sendmsg(int(fd), input, cmsg, nil, 0)
if err != nil {
return
}
_, err = api.Read(output)
return
}
func BuildCmsg(mode uint32, iv []byte) []byte {
cbuf := make([]byte, syscall.CmsgSpace(4)+syscall.CmsgSpace(20))
cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&cbuf[0]))
cmsg.Level = unix.SOL_ALG
cmsg.Type = unix.ALG_SET_OP
cmsg.SetLen(syscall.CmsgLen(4))
op := (*uint32)(unsafe.Pointer(CMSG_DATA(cmsg)))
*op = mode
cmsg = (*syscall.Cmsghdr)(unsafe.Pointer(&cbuf[syscall.CmsgSpace(4)]))
cmsg.Level = unix.SOL_ALG
cmsg.Type = unix.ALG_SET_IV
cmsg.SetLen(syscall.CmsgLen(20))
alg_iv := (*af_alg_iv)(unsafe.Pointer(CMSG_DATA(cmsg)))
alg_iv.ivlen = uint32(len(iv))
copy(alg_iv.iv[:], iv)
return cbuf
}
func CMSG_DATA(cmsg *syscall.Cmsghdr) unsafe.Pointer {
return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + uintptr(syscall.SizeofCmsghdr))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment