Changeset 256503 in webkit
- Timestamp:
- Feb 12, 2020 11:20:17 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r256502 r256503 1 2020-02-12 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com> 2 3 [WebCrypto][CommonCrypto] Incorrect AES-CTR with counterLength longer than 64 4 https://bugs.webkit.org/show_bug.cgi?id=207238 5 6 Reviewed by Jiewen Tan. 7 8 Add test cases where the counter length is 66 and 128, and the counter capacity 9 to overflow is 1 and 2. 10 * crypto/subtle/aes-ctr-import-key-encrypt-expected.txt: 11 * crypto/subtle/aes-ctr-import-key-encrypt.html: 12 1 13 2020-02-12 Lauro Moura <lmoura@igalia.com> 2 14 -
trunk/LayoutTests/crypto/subtle/aes-ctr-import-key-encrypt-expected.txt
r215051 r256503 12 12 Length = 2, overflow 13 13 PASS bytesToHexString(cipherText) is expectedCipherText4 14 Length = 2, overflow 15 PASS bytesToHexString(cipherText) is expectedCipherText5 14 16 Length = 8, overflow 15 PASS bytesToHexString(cipherText) is expectedCipherText5 17 PASS bytesToHexString(cipherText) is expectedCipherText6 18 Length = 8, overflow 19 PASS bytesToHexString(cipherText) is expectedCipherText7 20 Length = 64, overflow 21 PASS bytesToHexString(cipherText) is expectedCipherText8 22 Length = 64, overflow 23 PASS bytesToHexString(cipherText) is expectedCipherText9 24 Length = 66, overflow 25 PASS bytesToHexString(cipherText) is expectedCipherText10 26 Length = 66, overflow 27 PASS bytesToHexString(cipherText) is expectedCipherText11 28 Length = 128, overflow 29 PASS bytesToHexString(cipherText) is expectedCipherText12 30 Length = 128, overflow 31 PASS bytesToHexString(cipherText) is expectedCipherText13 16 32 PASS successfullyParsed is true 17 33 -
trunk/LayoutTests/crypto/subtle/aes-ctr-import-key-encrypt.html
r215051 r256503 33 33 var aesCtrParams4= { 34 34 name: "aes-ctr", 35 counter: asciiToUint8Array("jnOw99oOZFLIEPMr"),35 counter: hexStringToUint8Array("6a6e4f7739396f4f5a464c4945504dff"), 36 36 length: 2, 37 37 } 38 38 var aesCtrParams5= { 39 39 name: "aes-ctr", 40 counter: hexStringToUint8Array("6a6e4f7739396f4f5a464c4945504dfe"), 41 length: 2, 42 } 43 var aesCtrParams6= { 44 name: "aes-ctr", 40 45 counter: hexStringToUint8Array("6a6e4f7739396f4f5a464c4945504dff"), 41 46 length: 8, 42 47 } 48 var aesCtrParams7= { 49 name: "aes-ctr", 50 counter: hexStringToUint8Array("6a6e4f7739396f4f5a464c4945504dfe"), 51 length: 8, 52 } 53 var aesCtrParams8= { 54 name: "aes-ctr", 55 counter: hexStringToUint8Array("6a6e4f7739396f4fffffffffffffffff"), 56 length: 64, 57 } 58 var aesCtrParams9= { 59 name: "aes-ctr", 60 counter: hexStringToUint8Array("6a6e4f7739396f4ffffffffffffffffe"), 61 length: 64, 62 } 63 var aesCtrParams10= { 64 name: "aes-ctr", 65 counter: hexStringToUint8Array("6a6e4f7739396f7fffffffffffffffff"), 66 length: 66, 67 } 68 var aesCtrParams11= { 69 name: "aes-ctr", 70 counter: hexStringToUint8Array("6a6e4f7739396f7ffffffffffffffffe"), 71 length: 66, 72 } 73 var aesCtrParams12= { 74 name: "aes-ctr", 75 counter: hexStringToUint8Array("ffffffffffffffffffffffffffffffff"), 76 length: 128, 77 } 78 var aesCtrParams13= { 79 name: "aes-ctr", 80 counter: hexStringToUint8Array("fffffffffffffffffffffffffffffffe"), 81 length: 128, 82 } 43 83 var rawKey = asciiToUint8Array("jnOw99oOZFLIEPMr"); 44 84 var expectedCipherText = "a5f940e93406d4bd9b7318e653d4cb9d1af497f52fcbb659a038e711e8bd61fb4863931d25911e2e9ff30cf37ec27dd813a62830"; 45 var expectedCipherText4 = "a5f940e93406d4bd9b7318e653d4cb9d1af497f52fcbb659a038e711e8bd61fb96fed7fa5bf75d282a5477583b970b171740a2fa"; 46 var expectedCipherText5 = "6a461eb3f64ef4c466597ba877a9512bf224051c88ae885c565a7ada56843f3b84ec7596df67cbfdcfbeb275768f4d7270ce7ddf"; 85 var expectedCipherText4 = "6a461eb3f64ef4c466597ba877a9512b5ab41b4338edc2822d1f0dfac0cec07149766e189fa426d5ea30fe541018362088db2117"; 86 var expectedCipherText5 = "b2d2295a2fa06ef570752c7d1bc08fc64e4c5effce0da6ff6d0a5fa93a8d5b6b168c581103e691a62c5229f08082f8321b4d654b"; 87 var expectedCipherText6 = "6a461eb3f64ef4c466597ba877a9512bf224051c88ae885c565a7ada56843f3b84ec7596df67cbfdcfbeb275768f4d7270ce7ddf"; 88 var expectedCipherText7 = "b2d2295a2fa06ef570752c7d1bc08fc64e4c5effce0da6ff6d0a5fa93a8d5b6bbe1c464eb3a5db7857175ed016c80778d6d77ec5"; 89 var expectedCipherText8 = "3c37c5ea017d201bf608f86b0225c0d616d0e4f0ddd7aba96d4bb4ee3b829832b5ab2c2963d1d6b32ef3db59956bc15245b101c9"; 90 var expectedCipherText9 = "86253252027d2b6fd6c95d7849f51abc183d85a6393e7220fd5bdc6a4f01ca965ae8a7a2e6dcf88d6c0690e47bcea071e790277a"; 91 var expectedCipherText10 = "be0615c8485e2e7adc4e547b6aea98f59095547d42f9b1471edfe464152b1294f565b32c9ed385042291bec3e4ae312c3f32080b"; 92 var expectedCipherText11 = "48eef2dfe7c2d41d93747a2c9f5a50ad9a0c5584701d7c41d71d707a27ce92b5dcad172f79f2e2631f92c06e55672ad7a75eb87f"; 93 var expectedCipherText12 = "1065c7107fd33a3f1e05627238d30955055274f507c82716ccfb77f609446c07b1f07b80fc989b97be49007133953ad173a11cd7"; 94 var expectedCipherText13 = "b936426686f9d79bf53cf9bb6a810997346f875c479068041556467375f70315496a37a73cc37432cdb653fc49085444e3cb70d3"; 47 95 48 96 crypto.subtle.importKey("raw", rawKey, "aes-ctr", extractable, ["encrypt"]).then(function(result) { … … 77 125 shouldBe("bytesToHexString(cipherText)", "expectedCipherText4"); 78 126 79 debug("Length = 8, overflow");127 debug("Length = 2, overflow"); 80 128 return crypto.subtle.encrypt(aesCtrParams5, key, plainText); 81 129 }).then(function(result) { … … 83 131 84 132 shouldBe("bytesToHexString(cipherText)", "expectedCipherText5"); 133 134 debug("Length = 8, overflow"); 135 return crypto.subtle.encrypt(aesCtrParams6, key, plainText); 136 }).then(function(result) { 137 cipherText = result; 138 139 shouldBe("bytesToHexString(cipherText)", "expectedCipherText6"); 140 141 debug("Length = 8, overflow"); 142 return crypto.subtle.encrypt(aesCtrParams7, key, plainText); 143 }).then(function(result) { 144 cipherText = result; 145 146 shouldBe("bytesToHexString(cipherText)", "expectedCipherText7"); 147 148 debug("Length = 64, overflow"); 149 return crypto.subtle.encrypt(aesCtrParams8, key, plainText); 150 }).then(function(result) { 151 cipherText = result; 152 153 shouldBe("bytesToHexString(cipherText)", "expectedCipherText8"); 154 155 debug("Length = 64, overflow"); 156 return crypto.subtle.encrypt(aesCtrParams9, key, plainText); 157 }).then(function(result) { 158 cipherText = result; 159 160 shouldBe("bytesToHexString(cipherText)", "expectedCipherText9"); 161 162 debug("Length = 66, overflow"); 163 return crypto.subtle.encrypt(aesCtrParams10, key, plainText); 164 }).then(function(result) { 165 cipherText = result; 166 167 shouldBe("bytesToHexString(cipherText)", "expectedCipherText10"); 168 169 debug("Length = 66, overflow"); 170 return crypto.subtle.encrypt(aesCtrParams11, key, plainText); 171 }).then(function(result) { 172 cipherText = result; 173 174 shouldBe("bytesToHexString(cipherText)", "expectedCipherText11"); 175 176 debug("Length = 128, overflow"); 177 return crypto.subtle.encrypt(aesCtrParams12, key, plainText); 178 }).then(function(result) { 179 cipherText = result; 180 181 shouldBe("bytesToHexString(cipherText)", "expectedCipherText12"); 182 183 debug("Length = 128, overflow"); 184 return crypto.subtle.encrypt(aesCtrParams13, key, plainText); 185 }).then(function(result) { 186 cipherText = result; 187 188 shouldBe("bytesToHexString(cipherText)", "expectedCipherText13"); 85 189 86 190 finishJSTest(); -
trunk/Source/WebCore/ChangeLog
r256501 r256503 1 2020-02-12 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com> 2 3 [WebCrypto][CommonCrypto] Incorrect AES-CTR with counterLength longer than 64 4 https://bugs.webkit.org/show_bug.cgi?id=207238 5 6 Reviewed by Jiewen Tan. 7 8 Add CounterBlockHelper to calculate the remaining count for counter bits to overflow 9 and the whole counter block bits (nonce + zero counter bits) after overflow. 10 11 With this helper, simplify the AES-CTR implementation on CommonCrypto. 12 13 * crypto/algorithms/CryptoAlgorithmAES_CTR.cpp: 14 (WebCore::CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockHelper): 15 (WebCore::CryptoAlgorithmAES_CTR::CounterBlockHelper::countToOverflowSaturating const): 16 (WebCore::CryptoAlgorithmAES_CTR::CounterBlockHelper::counterVectorAfterOverflow const): 17 * crypto/algorithms/CryptoAlgorithmAES_CTR.h: 18 * crypto/mac/CryptoAlgorithmAES_CTRMac.cpp: 19 (WebCore::transformAES_CTR): 20 (WebCore::bigIntegerToSizeT): Deleted. 21 1 22 2020-02-12 Said Abou-Hallawa <sabouhallawa@apple.com> 2 23 -
trunk/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CTR.cpp
r238754 r256503 1 1 /* 2 2 * Copyright (C) 2017 Apple Inc. All rights reserved. 3 * Copyright (C) 2020 Sony Interactive Entertainment Inc. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 33 34 #include "CryptoKeyAES.h" 34 35 #include <wtf/CrossThreadCopier.h> 36 #include <wtf/FlipBytes.h> 35 37 36 38 namespace WebCore { … … 41 43 static const char* const ALG256 = "A256CTR"; 42 44 static const size_t CounterSize = 16; 45 static const uint64_t AllBitsSet = ~(uint64_t)0; 43 46 } 44 47 … … 201 204 } 202 205 206 CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockHelper(const Vector<uint8_t>& counterVector, size_t counterLength) 207 : m_counterLength(counterLength) 208 { 209 using namespace CryptoAlgorithmAES_CTRInternal; 210 211 ASSERT(counterVector.size() == CounterSize); 212 ASSERT(counterLength <= CounterSize * 8); 213 bool littleEndian = false; // counterVector is stored in big-endian. 214 memcpy(&m_bits.m_hi, counterVector.data(), 8); 215 m_bits.m_hi = flipBytesIfLittleEndian(m_bits.m_hi, littleEndian); 216 memcpy(&m_bits.m_lo, counterVector.data() + 8, 8); 217 m_bits.m_lo = flipBytesIfLittleEndian(m_bits.m_lo, littleEndian); 218 } 219 220 size_t CryptoAlgorithmAES_CTR::CounterBlockHelper::countToOverflowSaturating() const 221 { 222 CounterBlockBits counterMask; 223 counterMask.set(); 224 counterMask <<= m_counterLength; 225 counterMask = ~counterMask; 226 227 auto countMinusOne = ~m_bits & counterMask; 228 229 CounterBlockBits sizeTypeMask; 230 sizeTypeMask.set(); 231 sizeTypeMask <<= sizeof(size_t) * 8; 232 if ((sizeTypeMask & countMinusOne).any()) { 233 // Saturating to the size_t max since the count is greater than that. 234 return std::numeric_limits<size_t>::max(); 235 } 236 237 countMinusOne &= ~sizeTypeMask; 238 if (countMinusOne.all()) { 239 // As all bits are set, adding one would result in an overflow. 240 // Return size_t max instead. 241 return std::numeric_limits<size_t>::max(); 242 } 243 244 static_assert(sizeof(size_t) <= sizeof(uint64_t)); 245 return countMinusOne.m_lo + 1; 246 } 247 248 Vector<uint8_t> CryptoAlgorithmAES_CTR::CounterBlockHelper::counterVectorAfterOverflow() const 249 { 250 using namespace CryptoAlgorithmAES_CTRInternal; 251 252 CounterBlockBits nonceMask; 253 nonceMask.set(); 254 nonceMask <<= m_counterLength; 255 auto bits = m_bits & nonceMask; 256 257 bool littleEndian = false; // counterVector is stored in big-endian. 258 Vector<uint8_t> counterVector(CounterSize); 259 uint64_t hi = flipBytesIfLittleEndian(bits.m_hi, littleEndian); 260 memcpy(counterVector.data(), &hi, 8); 261 uint64_t lo = flipBytesIfLittleEndian(bits.m_lo, littleEndian); 262 memcpy(counterVector.data() + 8, &lo, 8); 263 264 return counterVector; 265 } 266 267 void CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::set() 268 { 269 using namespace CryptoAlgorithmAES_CTRInternal; 270 m_hi = AllBitsSet; 271 m_lo = AllBitsSet; 272 } 273 274 bool CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::all() const 275 { 276 using namespace CryptoAlgorithmAES_CTRInternal; 277 return m_hi == AllBitsSet && m_lo == AllBitsSet; 278 } 279 280 bool CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::any() const 281 { 282 return m_hi || m_lo; 283 } 284 285 auto CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::operator&(const CounterBlockBits& rhs) const -> CounterBlockBits 286 { 287 return { m_hi & rhs.m_hi, m_lo & rhs.m_lo }; 288 } 289 290 auto CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::operator~() const -> CounterBlockBits 291 { 292 return { ~m_hi, ~m_lo }; 293 } 294 295 auto CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::operator <<=(unsigned shift) -> CounterBlockBits& 296 { 297 if (shift < 64) { 298 m_hi = (m_hi << shift) | m_lo >> (64 - shift); 299 m_lo <<= shift; 300 } else if (shift < 128) { 301 shift -= 64; 302 m_hi = m_lo << shift; 303 m_lo = 0; 304 } else { 305 m_hi = 0; 306 m_lo = 0; 307 } 308 return *this; 309 } 310 311 auto CryptoAlgorithmAES_CTR::CounterBlockHelper::CounterBlockBits::operator &=(const CounterBlockBits& rhs) -> CounterBlockBits& 312 { 313 m_hi &= rhs.m_hi; 314 m_lo &= rhs.m_lo; 315 return *this; 316 } 317 203 318 } 204 319 -
trunk/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CTR.h
r238754 r256503 1 1 /* 2 2 * Copyright (C) 2017 Apple Inc. All rights reserved. 3 * Copyright (C) 2020 Sony Interactive Entertainment Inc. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 37 38 class CryptoAlgorithmAES_CTR final : public CryptoAlgorithm { 38 39 public: 40 class CounterBlockHelper { 41 public: 42 CounterBlockHelper(const Vector<uint8_t>& counterVector, size_t counterLength); 43 44 size_t countToOverflowSaturating() const; 45 Vector<uint8_t> counterVectorAfterOverflow() const; 46 47 private: 48 // 128 bits integer with miminum required operators. 49 struct CounterBlockBits { 50 void set(); 51 bool all() const; 52 bool any() const; 53 54 CounterBlockBits operator&(const CounterBlockBits&) const; 55 CounterBlockBits operator~() const; 56 CounterBlockBits& operator <<=(unsigned); 57 CounterBlockBits& operator &=(const CounterBlockBits&); 58 59 uint64_t m_hi { 0 }; 60 uint64_t m_lo { 0 }; 61 }; 62 63 CounterBlockBits m_bits; 64 const size_t m_counterLength; 65 }; 66 39 67 static constexpr const char* s_name = "AES-CTR"; 40 68 static constexpr CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::AES_CTR; -
trunk/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CTRMac.cpp
r238754 r256503 1 1 /* 2 2 * Copyright (C) 2017 Apple Inc. All rights reserved. 3 * Copyright (C) 2020 Sony Interactive Entertainment Inc. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 35 36 namespace WebCore { 36 37 37 // It takes the last WORDSIZE/8 bytes of the bigInteger and then convert them into a size_t value38 static size_t bigIntegerToSizeT(const Vector<uint8_t>& bigInteger)39 {40 size_t result = 0;41 for (size_t i = bigInteger.size() - (__WORDSIZE / 8); i < bigInteger.size(); ++i) {42 result <<= 8;43 result += bigInteger[i];44 }45 return result;46 }47 48 38 static ExceptionOr<Vector<uint8_t>> transformAES_CTR(CCOperation operation, const Vector<uint8_t>& counter, size_t counterLength, const Vector<uint8_t>& key, const Vector<uint8_t>& data) 49 39 { … … 53 43 // by the counterLength. It then increments the nonce which should stay same for the whole operation. To remedy this issue, 54 44 // we detect the overflow ahead and divide the operation into two parts. 55 // Ignore the case: counterLength > __WORDSIZE.56 45 size_t numberOfBlocks = data.size() % kCCBlockSizeAES128 ? data.size() / kCCBlockSizeAES128 + 1 : data.size() / kCCBlockSizeAES128; 46 57 47 // Detect loop 58 if (counterLength < __WORDSIZE&& numberOfBlocks > (1 << counterLength))48 if (counterLength < sizeof(size_t) * 8 && numberOfBlocks > (1 << counterLength)) 59 49 return Exception { OperationError }; 50 60 51 // Calculate capacity before overflow 61 size_t rightMost = bigIntegerToSizeT(counter); // convert right most __WORDSIZE bits into a size_t value, which is the longest counter we could possibly use. 62 size_t capacity = numberOfBlocks; // SIZE_MAX - counter 63 if (counterLength < __WORDSIZE) { 64 size_t mask = SIZE_MAX << counterLength; // Used to set nonce in rightMost(nonce + counter) to 1s 65 capacity = SIZE_MAX - (rightMost| mask) + 1; 66 } 67 if (counterLength == __WORDSIZE) 68 capacity = SIZE_MAX - rightMost + 1; 52 CryptoAlgorithmAES_CTR::CounterBlockHelper counterBlockHelper(counter, counterLength); 53 size_t capacity = counterBlockHelper.countToOverflowSaturating(); 69 54 70 55 // Divide data into two parts if necessary. … … 102 87 // second part: compute the remaining data and append them to the head. 103 88 // reset counter 104 Vector<uint8_t> remainingCounter(counter.size()); 105 size_t counterOffset = counterLength % 8; 106 size_t nonceOffset = counter.size() - counterLength / 8 - !!counterOffset; 107 memcpy(remainingCounter.data(), counter.data(), nonceOffset); // copy the nonce 108 // set the middle byte 109 if (!!counterOffset) { 110 size_t mask = SIZE_MAX << counterOffset; 111 remainingCounter[nonceOffset] = counter[nonceOffset] & mask; 112 } 113 memset(remainingCounter.data() + nonceOffset + !!counterOffset, 0, counterLength / 8); // reset the counter 114 89 Vector<uint8_t> remainingCounter = counterBlockHelper.counterVectorAfterOverflow(); 115 90 status = CCCryptorCreateWithMode(operation, kCCModeCTR, kCCAlgorithmAES128, ccNoPadding, remainingCounter.data(), key.data(), key.size(), 0, 0, 0, kCCModeOptionCTR_BE, &cryptor); 116 91 if (status)
Note: See TracChangeset
for help on using the changeset viewer.