github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/dcp/key.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 "crypto/aes" 14 "encoding/binary" 15 "errors" 16 17 "github.com/f-secure-foundry/tamago/bits" 18 "github.com/f-secure-foundry/tamago/dma" 19 "github.com/f-secure-foundry/tamago/internal/reg" 20 "github.com/f-secure-foundry/tamago/soc/imx6" 21 ) 22 23 // DeriveKeyMemory represents the DMA memory region used for exchanging DCP 24 // derived keys when the derivation index points to an internal DCP key RAM 25 // slot. 26 // 27 // The default value allocates a DMA region within the i.MX6 On-Chip RAM 28 // (OCRAM/iRAM) to avoid passing through external RAM. 29 // 30 // The DeriveKey() function uses DeriveKeyMemory only when the default DMA 31 // region is not already set within iRAM. 32 // 33 // Applications can override the region with an arbitrary one when the iRAM 34 // needs to be avoided or is already used as non-default DMA region. 35 var DeriveKeyMemory = &dma.Region{ 36 Start: imx6.IRAMStart, 37 Size: imx6.IRAMSize, 38 } 39 40 func init() { 41 DeriveKeyMemory.Init() 42 } 43 44 // DeriveKey derives a hardware unique key in a manner equivalent to PKCS#11 45 // C_DeriveKey with CKM_AES_CBC_ENCRYPT_DATA. 46 // 47 // The diversifier is AES-CBC encrypted using the internal OTPMK key (when SNVS 48 // is enabled). 49 // 50 // *WARNING*: when SNVS is not enabled a default non-unique test vector is used 51 // and therefore key derivation is *unsafe*, see imx6.SNVS(). 52 // 53 // A negative index argument results in the derived key being computed and 54 // returned. 55 // 56 // An index argument equal or greater than 0 moves the derived key directly to 57 // the corresponding internal DCP key RAM slot (see SetKey()). This is 58 // accomplished through an iRAM reserved DMA buffer, to ensure that the key is 59 // never exposed to external RAM or the Go runtime. In this case no key is 60 // returned by the function. 61 func DeriveKey(diversifier []byte, iv []byte, index int) (key []byte, err error) { 62 if len(iv) != aes.BlockSize { 63 return nil, errors.New("invalid IV size") 64 } 65 66 // prepare diversifier for in-place encryption 67 key = pad(diversifier, false) 68 69 region := dma.Default() 70 71 if index >= 0 { 72 // force use of iRAM if not already set as default DMA region 73 if !(region.Start > imx6.IRAMStart && region.Start < imx6.IRAMStart+imx6.IRAMSize) { 74 region = DeriveKeyMemory 75 } 76 } 77 78 pkt := &WorkPacket{} 79 pkt.SetCipherDefaults() 80 81 // Use device-specific hardware key for encryption. 82 pkt.Control0 |= 1 << DCP_CTRL0_CIPHER_ENCRYPT 83 pkt.Control0 |= 1 << DCP_CTRL0_OTP_KEY 84 pkt.Control1 |= KEY_SELECT_UNIQUE_KEY << DCP_CTRL1_KEY_SELECT 85 86 pkt.BufferSize = uint32(len(key)) 87 88 pkt.SourceBufferAddress = region.Alloc(key, aes.BlockSize) 89 defer region.Free(pkt.SourceBufferAddress) 90 91 pkt.DestinationBufferAddress = pkt.SourceBufferAddress 92 93 pkt.PayloadPointer = region.Alloc(iv, 0) 94 defer region.Free(pkt.PayloadPointer) 95 96 ptr := region.Alloc(pkt.Bytes(), 0) 97 defer region.Free(ptr) 98 99 err = cmd(ptr, 1) 100 101 if err != nil { 102 return nil, err 103 } 104 105 if index >= 0 { 106 err = setKeyData(index, nil, pkt.SourceBufferAddress) 107 } else { 108 region.Read(pkt.SourceBufferAddress, 0, key) 109 } 110 111 return 112 } 113 114 func setKeyData(index int, key []byte, addr uint32) (err error) { 115 var keyLocation uint32 116 var subword uint32 117 118 if index < 0 || index > 3 { 119 return errors.New("key index must be between 0 and 3") 120 } 121 122 if key != nil && len(key) > aes.BlockSize { 123 return errors.New("invalid key size") 124 } 125 126 bits.SetN(&keyLocation, KEY_INDEX, 0b11, uint32(index)) 127 128 mux.Lock() 129 defer mux.Unlock() 130 131 for subword < 4 { 132 off := subword * 4 133 134 bits.SetN(&keyLocation, KEY_SUBWORD, 0b11, subword) 135 reg.Write(DCP_KEY, keyLocation) 136 137 if key != nil { 138 k := key[off : off+4] 139 reg.Write(DCP_KEYDATA, binary.LittleEndian.Uint32(k)) 140 } else { 141 reg.Move(DCP_KEYDATA, addr+off) 142 } 143 144 subword++ 145 } 146 147 return 148 } 149 150 // SetKey configures an AES-128 key in one of the 4 available slots of the DCP 151 // key RAM. 152 func SetKey(index int, key []byte) (err error) { 153 return setKeyData(index, key, 0) 154 }