github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/dcp/cipher.go (about) 1 // NXP Data Co-Processor (DCP) driver 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) F-Secure Corporation 5 // https://foundry.f-secure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package dcp 11 12 import ( 13 "bytes" 14 "crypto/aes" 15 "errors" 16 17 "github.com/f-secure-foundry/tamago/bits" 18 "github.com/f-secure-foundry/tamago/dma" 19 ) 20 21 // SetCipherDefaults initializes default values for a DCP work packet that 22 // performs cipher operation. 23 func (pkt *WorkPacket) SetCipherDefaults() { 24 pkt.Control0 |= 1 << DCP_CTRL0_INTERRUPT_ENABL 25 pkt.Control0 |= 1 << DCP_CTRL0_DECR_SEMAPHORE 26 pkt.Control0 |= 1 << DCP_CTRL0_ENABLE_CIPHER 27 pkt.Control0 |= 1 << DCP_CTRL0_CIPHER_INIT 28 29 pkt.Control1 |= CIPHER_SELECT_AES128 << DCP_CTRL1_CIPHER_SELECT 30 pkt.Control1 |= CIPHER_MODE_CBC << DCP_CTRL1_CIPHER_MODE 31 } 32 33 func cipher(buf []byte, index int, iv []byte, enc bool) (err error) { 34 if len(buf)%aes.BlockSize != 0 { 35 return errors.New("invalid input size") 36 } 37 38 if index < 0 || index > 3 { 39 return errors.New("key index must be between 0 and 3") 40 } 41 42 if len(iv) != aes.BlockSize { 43 return errors.New("invalid IV size") 44 } 45 46 pkt := &WorkPacket{} 47 pkt.SetCipherDefaults() 48 49 if enc { 50 pkt.Control0 |= 1 << DCP_CTRL0_CIPHER_ENCRYPT 51 } 52 53 // use key RAM slot 54 pkt.Control1 |= (uint32(index) & 0xff) << DCP_CTRL1_KEY_SELECT 55 56 pkt.BufferSize = uint32(len(buf)) 57 58 pkt.SourceBufferAddress = dma.Alloc(buf, aes.BlockSize) 59 defer dma.Free(pkt.SourceBufferAddress) 60 61 pkt.DestinationBufferAddress = pkt.SourceBufferAddress 62 63 pkt.PayloadPointer = dma.Alloc(iv, 4) 64 defer dma.Free(pkt.PayloadPointer) 65 66 ptr := dma.Alloc(pkt.Bytes(), 4) 67 defer dma.Free(ptr) 68 69 err = cmd(ptr, 1) 70 71 if err != nil { 72 return 73 } 74 75 dma.Read(pkt.DestinationBufferAddress, 0, buf) 76 77 return 78 } 79 80 // Encrypt performs in-place buffer encryption using AES-128-CBC, the key can 81 // be selected with the index argument from one previously set with SetKey(). 82 func Encrypt(buf []byte, index int, iv []byte) (err error) { 83 return cipher(buf, index, iv, true) 84 } 85 86 // Decrypt performs in-place buffer decryption using AES-128-CBC, the key can 87 // be selected with the index argument from one previously set with SetKey(). 88 func Decrypt(buf []byte, index int, iv []byte) (err error) { 89 return cipher(buf, index, iv, false) 90 } 91 92 // CipherChain performs chained in-place buffer encryption/decryption using 93 // AES-128-CBC, the key can be selected with the index argument from one 94 // previously set with SetKey(). 95 // 96 // The function expects a byte array with concatenated input data and a byte 97 // array with concatenated initialization vectors, the count and size arguments 98 // should reflect the number of slices, each to be ciphered and with the 99 // corresponding initialization vector slice. 100 func CipherChain(buf []byte, ivs []byte, count int, size int, index int, enc bool) (err error) { 101 if len(buf) != size*count || len(buf)%aes.BlockSize != 0 { 102 return errors.New("invalid input size") 103 } 104 105 if len(ivs) != aes.BlockSize*count { 106 return errors.New("invalid IV size") 107 } 108 109 if index < 0 || index > 3 { 110 return errors.New("key index must be between 0 and 3") 111 } 112 113 src := dma.Alloc(buf, aes.BlockSize) 114 defer dma.Free(src) 115 116 payloads := dma.Alloc(ivs, 4) 117 defer dma.Free(payloads) 118 119 pkts, pktBuf := dma.Reserve(WorkPacketLength*count, 4) 120 defer dma.Release(pkts) 121 122 pkt := &WorkPacket{} 123 pkt.SetCipherDefaults() 124 pkt.Control0 |= 1 << DCP_CTRL0_CHAIN 125 pkt.BufferSize = uint32(size) 126 127 bits.Clear(&pkt.Control0, DCP_CTRL0_INTERRUPT_ENABL) 128 129 if enc { 130 pkt.Control0 |= 1 << DCP_CTRL0_CIPHER_ENCRYPT 131 } 132 133 // use key RAM slot 134 pkt.Control1 |= (uint32(index) & 0xff) << DCP_CTRL1_KEY_SELECT 135 136 for i := 0; i < count; i++ { 137 pkt.SourceBufferAddress = src + uint32(i*size) 138 pkt.DestinationBufferAddress = pkt.SourceBufferAddress 139 pkt.PayloadPointer = payloads + uint32(i*aes.BlockSize) 140 141 if i < count-1 { 142 pkt.NextCmdAddr = pkts + uint32((i+1)*WorkPacketLength) 143 } else { 144 bits.Clear(&pkt.Control0, DCP_CTRL0_CHAIN) 145 bits.Set(&pkt.Control0, DCP_CTRL0_INTERRUPT_ENABL) 146 } 147 148 copy(pktBuf[i*WorkPacketLength:], pkt.Bytes()) 149 } 150 151 err = cmd(pkts, count) 152 153 if err != nil { 154 return 155 } 156 157 dma.Read(src, 0, buf) 158 159 return 160 } 161 162 func pad(buf []byte, extraBlock bool) []byte { 163 padLen := 0 164 r := len(buf) % aes.BlockSize 165 166 if r != 0 { 167 padLen = aes.BlockSize - r 168 } else if extraBlock { 169 padLen = aes.BlockSize 170 } 171 172 padding := []byte{(byte)(padLen)} 173 padding = bytes.Repeat(padding, padLen) 174 175 return append(buf, padding...) 176 }