Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: talitos - Work around SEC6 ERRATA (AES-CTR mode data size error)

Talitos Security Engine AESU considers any input
data size that is not a multiple of 16 bytes to be an error.
This is not a problem in general, except for Counter mode
that is a stream cipher and can have an input of any size.

Test Manager for ctr(aes) fails on 4th test vector which has
a length of 499 while all previous vectors which have a 16 bytes
multiple length succeed.

As suggested by Freescale, round up the input data length to the
nearest 16 bytes.

Fixes: 5e75ae1b3cef ("crypto: talitos - add new crypto modes")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Christophe Leroy and committed by
Herbert Xu
416b8467 bc005983

+17 -12
+16 -12
drivers/crypto/talitos.c
··· 1093 1093 */ 1094 1094 static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count, 1095 1095 unsigned int offset, int datalen, int elen, 1096 - struct talitos_ptr *link_tbl_ptr) 1096 + struct talitos_ptr *link_tbl_ptr, int align) 1097 1097 { 1098 1098 int n_sg = elen ? sg_count + 1 : sg_count; 1099 1099 int count = 0; 1100 1100 int cryptlen = datalen + elen; 1101 + int padding = ALIGN(cryptlen, align) - cryptlen; 1101 1102 1102 1103 while (cryptlen && sg && n_sg--) { 1103 1104 unsigned int len = sg_dma_len(sg); ··· 1122 1121 offset += datalen; 1123 1122 } 1124 1123 to_talitos_ptr(link_tbl_ptr + count, 1125 - sg_dma_address(sg) + offset, len, 0); 1124 + sg_dma_address(sg) + offset, sg_next(sg) ? len : len + padding, 0); 1126 1125 to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0); 1127 1126 count++; 1128 1127 cryptlen -= len; ··· 1145 1144 unsigned int len, struct talitos_edesc *edesc, 1146 1145 struct talitos_ptr *ptr, int sg_count, 1147 1146 unsigned int offset, int tbl_off, int elen, 1148 - bool force) 1147 + bool force, int align) 1149 1148 { 1150 1149 struct talitos_private *priv = dev_get_drvdata(dev); 1151 1150 bool is_sec1 = has_ftr_sec1(priv); 1151 + int aligned_len = ALIGN(len, align); 1152 1152 1153 1153 if (!src) { 1154 1154 to_talitos_ptr(ptr, 0, 0, is_sec1); ··· 1157 1155 } 1158 1156 to_talitos_ptr_ext_set(ptr, elen, is_sec1); 1159 1157 if (sg_count == 1 && !force) { 1160 - to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1); 1158 + to_talitos_ptr(ptr, sg_dma_address(src) + offset, aligned_len, is_sec1); 1161 1159 return sg_count; 1162 1160 } 1163 1161 if (is_sec1) { 1164 - to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1); 1162 + to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, aligned_len, is_sec1); 1165 1163 return sg_count; 1166 1164 } 1167 1165 sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len, elen, 1168 - &edesc->link_tbl[tbl_off]); 1166 + &edesc->link_tbl[tbl_off], align); 1169 1167 if (sg_count == 1 && !force) { 1170 1168 /* Only one segment now, so no link tbl needed*/ 1171 1169 copy_talitos_ptr(ptr, &edesc->link_tbl[tbl_off], is_sec1); 1172 1170 return sg_count; 1173 1171 } 1174 1172 to_talitos_ptr(ptr, edesc->dma_link_tbl + 1175 - tbl_off * sizeof(struct talitos_ptr), len, is_sec1); 1173 + tbl_off * sizeof(struct talitos_ptr), aligned_len, is_sec1); 1176 1174 to_talitos_ptr_ext_or(ptr, DESC_PTR_LNKTBL_JUMP, is_sec1); 1177 1175 1178 1176 return sg_count; ··· 1184 1182 unsigned int offset, int tbl_off) 1185 1183 { 1186 1184 return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset, 1187 - tbl_off, 0, false); 1185 + tbl_off, 0, false, 1); 1188 1186 } 1189 1187 1190 1188 /* ··· 1253 1251 1254 1252 ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4], 1255 1253 sg_count, areq->assoclen, tbl_off, elen, 1256 - false); 1254 + false, 1); 1257 1255 1258 1256 if (ret > 1) { 1259 1257 tbl_off += ret; ··· 1273 1271 elen = 0; 1274 1272 ret = talitos_sg_map_ext(dev, areq->dst, cryptlen, edesc, &desc->ptr[5], 1275 1273 sg_count, areq->assoclen, tbl_off, elen, 1276 - is_ipsec_esp && !encrypt); 1274 + is_ipsec_esp && !encrypt, 1); 1277 1275 tbl_off += ret; 1278 1276 1279 1277 if (!encrypt && is_ipsec_esp) { ··· 1579 1577 bool sync_needed = false; 1580 1578 struct talitos_private *priv = dev_get_drvdata(dev); 1581 1579 bool is_sec1 = has_ftr_sec1(priv); 1580 + bool is_ctr = (desc->hdr & DESC_HDR_SEL0_MASK) == DESC_HDR_SEL0_AESU && 1581 + (desc->hdr & DESC_HDR_MODE0_AESU_MASK) == DESC_HDR_MODE0_AESU_CTR; 1582 1582 1583 1583 /* first DWORD empty */ 1584 1584 ··· 1601 1597 /* 1602 1598 * cipher in 1603 1599 */ 1604 - sg_count = talitos_sg_map(dev, areq->src, cryptlen, edesc, 1605 - &desc->ptr[3], sg_count, 0, 0); 1600 + sg_count = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[3], 1601 + sg_count, 0, 0, 0, false, is_ctr ? 16 : 1); 1606 1602 if (sg_count > 1) 1607 1603 sync_needed = true; 1608 1604
+1
drivers/crypto/talitos.h
··· 344 344 345 345 /* primary execution unit mode (MODE0) and derivatives */ 346 346 #define DESC_HDR_MODE0_ENCRYPT cpu_to_be32(0x00100000) 347 + #define DESC_HDR_MODE0_AESU_MASK cpu_to_be32(0x00600000) 347 348 #define DESC_HDR_MODE0_AESU_CBC cpu_to_be32(0x00200000) 348 349 #define DESC_HDR_MODE0_AESU_CTR cpu_to_be32(0x00600000) 349 350 #define DESC_HDR_MODE0_DEU_CBC cpu_to_be32(0x00400000)