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