* void CBCDecrypt(byte[] iv, byte[] data, int off, int len)
* uint CTRRun(byte[] iv, uint cc, byte[] data)
* uint CTRRun(byte[] iv, uint cc, byte[] data, int off, int len)
+ * void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt, byte[] data)
+ * void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt,
+ * byte[] data, int off, int len)
* Note that CBCEncrypt(byte[],byte[]) (respectively
- * CBCDecrypt(byte[],byte[]) and CTRRun(byte[],uint,byte[])) simply
- * calls CBCEncrypt(byte[],byte[],int,int) (respectively
- * CBCDecrypt(byte[],byte[],int,int) and
- * CTRRun(byte[],uint,byte[],int,int)) so implementations who wish to
- * override these methods may content themselves with overriding the two
- * methods with the "off" and "len" extra parameters.
+ * CBCDecrypt(byte[],byte[]), CTRRun(byte[],uint,byte[]) and
+ * CTRCBCRun(byte[],byte[],bool,byte[])) simply calls
+ * CBCEncrypt(byte[],byte[],int,int) (respectively
+ * CBCDecrypt(byte[],byte[],int,int), CTRRun(byte[],uint,byte[],int,int)
+ * and CTRCBCRun(byte[],byte[],bool,byte[],int,int)) so implementations
+ * who wish to override these methods may content themselves with
+ * overriding the four methods with the "off" and "len" extra parameters.
*/
public abstract class BlockCipherCore : IBlockCipher {
return cc;
}
+ /*
+ * This method is implemented by calling
+ * CTRCBCRun(byte[],byte[],bool,byte[],int,int).
+ */
+ public virtual void CTRCBCRun(byte[] ctr, byte[] cbcmac,
+ bool encrypt, byte[] data)
+ {
+ CTRCBCRun(ctr, cbcmac, encrypt, data, 0, data.Length);
+ }
+
+ /* see IBlockCipher */
+ public virtual void CTRCBCRun(byte[] ctr, byte[] cbcmac,
+ bool encrypt, byte[] data, int off, int len)
+ {
+ if (!encrypt) {
+ CBCMac(cbcmac, data, off, len);
+ }
+ DoCTRFull(ctr, data, off, len);
+ if (encrypt) {
+ CBCMac(cbcmac, data, off, len);
+ }
+ }
+
+ void DoCTRFull(byte[] ctr, byte[] data, int off, int len)
+ {
+ int blen = BlockSize;
+ if (ctr.Length != blen) {
+ throw new CryptoException("wrong counter length");
+ }
+ while (len > 0) {
+ Array.Copy(ctr, 0, tmp, 0, blen);
+ uint cc = 1;
+ for (int i = blen - 1; i >= 0; i --) {
+ uint x = ctr[i] + cc;
+ ctr[i] = (byte)x;
+ cc = x >> 8;
+ }
+ BlockEncrypt(tmp, 0);
+ int clen = Math.Min(blen, len);
+ for (int i = 0; i < clen; i ++) {
+ data[off + i] ^= tmp[i];
+ }
+ off += clen;
+ len -= clen;
+ }
+ }
+
+ /* see IBlockCipher */
+ public void CBCMac(byte[] cbcmac, byte[] data, int off, int len)
+ {
+ int blen = BlockSize;
+ if (cbcmac.Length != blen) {
+ throw new CryptoException("wrong MAC length");
+ }
+ while (len > 0) {
+ for (int i = 0; i < blen; i ++) {
+ cbcmac[i] ^= data[off + i];
+ }
+ BlockEncrypt(cbcmac, 0);
+ off += blen;
+ len -= blen;
+ }
+ }
+
/* see IBlockCipher */
public abstract IBlockCipher Dup();
}
*/
uint CTRRun(byte[] iv, uint cc, byte[] data, int off, int len);
+ /*
+ * Do combined CTR encryption/decryption and CBC-MAC. The CTR
+ * mode uses full-block increments (counter value is the
+ * big-endian interpretation of the complete block); the ctr[]
+ * array contains the initial value for the counter (used to
+ * encrypt or decrypt the full block) and it is updated by
+ * this method as blocks are processed.
+ *
+ * The cbcmac[] array has full block width and contains the
+ * running value for CBC-MAC, computed over the _encrypted_ data.
+ *
+ * The flag 'encrypt' is true when encrypting, false when
+ * decrypting. Note that CTR encryption and decryption are
+ * identical; thus, the only effect of this flag is to decide
+ * whether CBC-MAC should be applied on the blocks before or
+ * after CTR encryption/decryption.
+ *
+ * The data is provided in the data[] buffer, and is
+ * encrypted/decrypted in place. Its length MUST be a multiple
+ * of the block size.
+ */
+ void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt, byte[] data);
+
+ /*
+ * Do combined CTR encryption/decryption and CBC-MAC. The CTR
+ * mode uses full-block increments (counter value is the
+ * big-endian interpretation of the complete block); the ctr[]
+ * array contains the initial value for the counter (used to
+ * encrypt or decrypt the full block) and it is updated by
+ * this method as blocks are processed.
+ *
+ * The cbcmac[] array has full block width and contains the
+ * running value for CBC-MAC, computed over the _encrypted_ data.
+ *
+ * The flag 'encrypt' is true when encrypting, false when
+ * decrypting. Note that CTR encryption and decryption are
+ * identical; thus, the only effect of this flag is to decide
+ * whether CBC-MAC should be applied on the blocks before or
+ * after CTR encryption/decryption.
+ *
+ * The data is provided in the data[] buffer, and is
+ * encrypted/decrypted in place. Its length MUST be a multiple
+ * of the block size.
+ */
+ void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt,
+ byte[] data, int off, int len);
+
+ /*
+ * Perform CBC-MAC: the cbcmac[] block is updated with the
+ * CBC-MAC of the data. Data length must be a multiple of the
+ * block size.
+ */
+ void CBCMac(byte[] cbcmac, byte[] data, int off, int len);
+
/*
* Duplicate this engine. This creates a new, independent
* instance that implements the same function, and starts with
--- /dev/null
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Text;
+
+using Crypto;
+
+namespace SSLTLS {
+
+internal class RecordDecryptCCM : RecordDecrypt {
+
+ IBlockCipher bc;
+ byte[] iv;
+ ulong seq;
+ byte[] tmp, tag, ctr, cbcmac;
+ bool ccm8;
+
+ internal RecordDecryptCCM(IBlockCipher bc, byte[] iv, bool ccm8)
+ {
+ this.bc = bc;
+ this.iv = new byte[12];
+ Array.Copy(iv, 0, this.iv, 0, 4);
+ seq = 0;
+ tag = new byte[16];
+ tmp = new byte[32];
+ ctr = new byte[16];
+ cbcmac = new byte[16];
+ this.ccm8 = ccm8;
+ }
+
+ internal override bool CheckLength(int len)
+ {
+ int tagLen = ccm8 ? 8 : 16;
+ return len >= (8 + tagLen) && len <= (16384 + 8 + tagLen);
+ }
+
+ internal override bool Decrypt(int recordType, int version,
+ byte[] data, ref int off, ref int len)
+ {
+ Array.Copy(data, off, iv, 4, 8);
+ off += 8;
+ len -= ccm8 ? 16 : 24;
+
+ /*
+ * Assemble block B0 and AAD.
+ */
+ tmp[0] = (byte)(0x40 | ((ccm8 ? 6 : 14) << 2) | 2);
+ Array.Copy(iv, 0, tmp, 1, 12);
+ tmp[13] = 0;
+ IO.Enc16be(len, tmp, 14);
+
+ tmp[16] = 0;
+ tmp[17] = 13;
+ IO.Enc64be(seq, tmp, 18);
+ IO.WriteHeader(recordType, version, len, tmp, 26);
+ tmp[31] = 0;
+ seq ++;
+
+ for (int i = 0; i < cbcmac.Length; i ++) {
+ cbcmac[i] = 0;
+ }
+ bc.CBCMac(cbcmac, tmp, 0, 32);
+
+ /*
+ * Make initial counter value, and compute tag mask.
+ * Since the counter least significant byte has value 0,
+ * getting it to the next value is simple and requires
+ * no carry propagation.
+ */
+ ctr[0] = 2;
+ Array.Copy(iv, 0, ctr, 1, 12);
+ for (int i = 13; i < 16; i ++) {
+ ctr[i] = 0;
+ }
+ Array.Copy(ctr, 0, tag, 0, 16);
+ bc.BlockEncrypt(tag);
+ ctr[15] = 1;
+
+ /*
+ * Perform CTR decryption, and compute CBC-MAC. Since
+ * CBC-MAC requires full blocks, we have to do the
+ * processing of the last partial block in a temporary
+ * buffer. The CBC-MAC is computed on the plaintext,
+ * padded with zeros in the last block.
+ */
+ int len1 = len & ~15;
+ int len2 = len - len1;
+ bc.CTRCBCRun(ctr, cbcmac, true, data, off, len1);
+ if (len2 > 0) {
+ bc.BlockEncrypt(ctr);
+ for (int i = 0; i < len2; i ++) {
+ data[off + len1 + i] ^= ctr[i];
+ }
+ Array.Copy(data, off + len1, tmp, 0, len2);
+ for (int i = len2; i < 16; i ++) {
+ tmp[i] = 0;
+ }
+ bc.CBCMac(cbcmac, tmp, 0, 16);
+ }
+
+ /*
+ * Check that the record MAC matches the expected value
+ * (taking into account the tag mask).
+ */
+ int z = 0;
+ for (int i = 0; i < (ccm8 ? 8 : 16); i ++) {
+ z |= cbcmac[i] ^ tag[i] ^ data[off + len + i];
+ }
+ return z == 0;
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Text;
+
+using Crypto;
+
+namespace SSLTLS {
+
+internal class RecordEncryptCCM : RecordEncrypt {
+
+ IBlockCipher bc;
+ byte[] iv;
+ ulong seq;
+ byte[] tmp, tag, ctr, cbcmac;
+ bool ccm8;
+
+ internal RecordEncryptCCM(IBlockCipher bc, byte[] iv, bool ccm8)
+ {
+ this.bc = bc;
+ this.iv = new byte[4];
+ Array.Copy(iv, 0, this.iv, 0, 4);
+ seq = 0;
+ tag = new byte[16];
+ tmp = new byte[32];
+ ctr = new byte[16];
+ cbcmac = new byte[16];
+ this.ccm8 = ccm8;
+ }
+
+ internal override void GetMaxPlaintext(ref int start, ref int end)
+ {
+ /*
+ * We need room at the start for the record header (5 bytes)
+ * and the explicit nonce (8 bytes). We need room at the end
+ * for the MAC (16 bytes).
+ */
+ start += 13;
+ end -= ccm8 ? 8 : 16;
+ int len = Math.Min(end - start, 16384);
+ end = start + len;
+ }
+
+ internal override void Encrypt(int recordType, int version,
+ byte[] data, ref int off, ref int len)
+ {
+ /*
+ * CBC-MAC starts with block B0, that encodes the
+ * nonce, tag length, and data length.
+ * It is then followed by the AAD:
+ * - AAD header (length, over 2 bytes in our case)
+ * - TLS sequence number (8 bytes)
+ * - plain record header
+ */
+ tmp[0] = (byte)(0x40 | ((ccm8 ? 6 : 14) << 2) | 2);
+ Array.Copy(iv, 0, tmp, 1, 4);
+ IO.Enc64be(seq, tmp, 5);
+ tmp[13] = 0;
+ IO.Enc16be(len, tmp, 14);
+
+ tmp[16] = 0;
+ tmp[17] = 13;
+ IO.Enc64be(seq, tmp, 18);
+ IO.WriteHeader(recordType, version, len, tmp, 26);
+ tmp[31] = 0;
+
+ for (int i = 0; i < cbcmac.Length; i ++) {
+ cbcmac[i] = 0;
+ }
+ bc.CBCMac(cbcmac, tmp, 0, 32);
+
+ /*
+ * Make initial counter value, and compute tag mask.
+ * Since the counter least significant byte has value 0,
+ * getting it to the next value is simple and requires
+ * no carry propagation.
+ */
+ ctr[0] = 2;
+ Array.Copy(tmp, 1, ctr, 1, 12);
+ for (int i = 13; i < 16; i ++) {
+ ctr[i] = 0;
+ }
+ Array.Copy(ctr, 0, tag, 0, 16);
+ bc.BlockEncrypt(tag);
+ ctr[15] = 1;
+
+ /*
+ * Perform CTR encryption and CBC-MAC. CCM is defined
+ * to use CBC-MAC on the plaintext, not the ciphertext,
+ * thus we need to set the 'encrypt' flag to false.
+ *
+ * When the last block is partial, then we must pad
+ * the plaintext with zeros, and compute the CBC-MAC
+ * on that plaintext.
+ */
+ int len1 = len & ~15;
+ int len2 = len - len1;
+ bc.CTRCBCRun(ctr, cbcmac, false, data, off, len1);
+ if (len2 > 0) {
+ Array.Copy(data, off + len1, tmp, 0, len2);
+ for (int i = len2; i < 16; i ++) {
+ tmp[i] = 0;
+ }
+ bc.CBCMac(cbcmac, tmp, 0, 16);
+ bc.BlockEncrypt(ctr);
+ for (int i = 0; i < len2; i ++) {
+ data[off + len1 + i] ^= ctr[i];
+ }
+ }
+
+ /*
+ * XOR the CBC-MAC output with the tag mask.
+ */
+ for (int i = 0; i < (ccm8 ? 8 : 16); i ++) {
+ data[off + len + i] = (byte)(tag[i] ^ cbcmac[i]);
+ }
+
+ /*
+ * Encode the header, and adjust offset / length.
+ */
+ off -= 13;
+ len += ccm8 ? 16 : 24;
+ IO.WriteHeader(recordType, version, len, data, off);
+ IO.Enc64be(seq, data, off + 5);
+ len += 5;
+
+ seq ++;
+ }
+}
+
+}
public const int ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031;
public const int ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032;
+ /* From RFC 6655 and 7251 */
+ public const int RSA_WITH_AES_128_CCM = 0xC09C;
+ public const int RSA_WITH_AES_256_CCM = 0xC09D;
+ public const int RSA_WITH_AES_128_CCM_8 = 0xC0A0;
+ public const int RSA_WITH_AES_256_CCM_8 = 0xC0A1;
+ public const int ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC;
+ public const int ECDHE_ECDSA_WITH_AES_256_CCM = 0xC0AD;
+ public const int ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE;
+ public const int ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF;
+
/* From RFC 7905 */
public const int ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8;
public const int ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9;
return "ECDH_RSA_WITH_AES_128_GCM_SHA256";
case ECDH_RSA_WITH_AES_256_GCM_SHA384:
return "ECDH_RSA_WITH_AES_256_GCM_SHA384";
+ case RSA_WITH_AES_128_CCM:
+ return "RSA_WITH_AES_128_CCM";
+ case RSA_WITH_AES_256_CCM:
+ return "RSA_WITH_AES_256_CCM";
+ case RSA_WITH_AES_128_CCM_8:
+ return "RSA_WITH_AES_128_CCM_8";
+ case RSA_WITH_AES_256_CCM_8:
+ return "RSA_WITH_AES_256_CCM_8";
+ case ECDHE_ECDSA_WITH_AES_128_CCM:
+ return "ECDHE_ECDSA_WITH_AES_128_CCM";
+ case ECDHE_ECDSA_WITH_AES_256_CCM:
+ return "ECDHE_ECDSA_WITH_AES_256_CCM";
+ case ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ return "ECDHE_ECDSA_WITH_AES_128_CCM_8";
+ case ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ return "ECDHE_ECDSA_WITH_AES_256_CCM_8";
case ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
case ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return ECDH_RSA_WITH_AES_128_GCM_SHA256;
case "ECDHRSAWITHAES256GCMSHA384":
return ECDH_RSA_WITH_AES_256_GCM_SHA384;
+ case "RSAWITHAES128CCM":
+ return RSA_WITH_AES_128_CCM;
+ case "RSAWITHAES256CCM":
+ return RSA_WITH_AES_256_CCM;
+ case "RSAWITHAES128CCM8":
+ return RSA_WITH_AES_128_CCM_8;
+ case "RSAWITHAES256CCM8":
+ return RSA_WITH_AES_256_CCM_8;
+ case "ECDHEECDSAWITHAES128CCM":
+ return ECDHE_ECDSA_WITH_AES_128_CCM;
+ case "ECDHEECDSAWITHAES256CCM":
+ return ECDHE_ECDSA_WITH_AES_256_CCM;
+ case "ECDHEECDSAWITHAES128CCM8":
+ return ECDHE_ECDSA_WITH_AES_128_CCM_8;
+ case "ECDHEECDSAWITHAES256CCM8":
+ return ECDHE_ECDSA_WITH_AES_256_CCM_8;
case "ECDHERSAWITHCHACHA20POLY1305SHA256":
return ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
case "ECDHEECDSAWITHCHACHA20POLY1305SHA256":
case RSA_WITH_AES_256_CBC_SHA256:
case RSA_WITH_AES_128_GCM_SHA256:
case RSA_WITH_AES_256_GCM_SHA384:
+ case RSA_WITH_AES_128_CCM:
+ case RSA_WITH_AES_256_CCM:
+ case RSA_WITH_AES_128_CCM_8:
+ case RSA_WITH_AES_256_CCM_8:
return true;
default:
return false;
case ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
case ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
case ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case ECDHE_ECDSA_WITH_AES_128_CCM:
+ case ECDHE_ECDSA_WITH_AES_256_CCM:
+ case ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case ECDHE_ECDSA_WITH_AES_256_CCM_8:
case ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return true;
default:
case ECDHE_RSA_WITH_AES_256_GCM_SHA384:
case ECDH_RSA_WITH_AES_128_GCM_SHA256:
case ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case RSA_WITH_AES_128_CCM:
+ case RSA_WITH_AES_256_CCM:
+ case RSA_WITH_AES_128_CCM_8:
+ case RSA_WITH_AES_256_CCM_8:
+ case ECDHE_ECDSA_WITH_AES_128_CCM:
+ case ECDHE_ECDSA_WITH_AES_256_CCM:
+ case ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case ECDHE_ECDSA_WITH_AES_256_CCM_8:
case ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
case DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
SSL.ECDHE_RSA_WITH_AES_128_GCM_SHA256,
SSL.ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
SSL.ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ SSL.ECDHE_ECDSA_WITH_AES_128_CCM,
+ SSL.ECDHE_ECDSA_WITH_AES_256_CCM,
+ SSL.ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ SSL.ECDHE_ECDSA_WITH_AES_256_CCM_8,
SSL.ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
SSL.ECDHE_RSA_WITH_AES_128_CBC_SHA256,
SSL.ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
SSL.RSA_WITH_AES_128_GCM_SHA256,
SSL.RSA_WITH_AES_256_GCM_SHA384,
+ SSL.RSA_WITH_AES_128_CCM,
+ SSL.RSA_WITH_AES_256_CCM,
+ SSL.RSA_WITH_AES_128_CCM_8,
+ SSL.RSA_WITH_AES_256_CCM_8,
SSL.RSA_WITH_AES_128_CBC_SHA256,
SSL.RSA_WITH_AES_256_CBC_SHA256,
SSL.RSA_WITH_AES_128_CBC_SHA,
IBlockCipher block = null;
IDigest hash = null;
Poly1305 pp = null;
+ bool isCCM = false;
+ bool isCCM8 = false;
switch (CipherSuite) {
case SSL.RSA_WITH_3DES_EDE_CBC_SHA:
case SSL.DH_DSS_WITH_3DES_EDE_CBC_SHA:
block = new AES();
break;
+ case SSL.RSA_WITH_AES_128_CCM:
+ case SSL.ECDHE_ECDSA_WITH_AES_128_CCM:
+ macLen = 0;
+ encLen = 16;
+ ivLen = 4;
+ block = new AES();
+ isCCM = true;
+ break;
+
+ case SSL.RSA_WITH_AES_256_CCM:
+ case SSL.ECDHE_ECDSA_WITH_AES_256_CCM:
+ macLen = 0;
+ encLen = 32;
+ ivLen = 4;
+ block = new AES();
+ isCCM = true;
+ break;
+
+ case SSL.RSA_WITH_AES_128_CCM_8:
+ case SSL.ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ macLen = 0;
+ encLen = 16;
+ ivLen = 4;
+ block = new AES();
+ isCCM8 = true;
+ break;
+
+ case SSL.RSA_WITH_AES_256_CCM_8:
+ case SSL.ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ macLen = 0;
+ encLen = 32;
+ ivLen = 4;
+ block = new AES();
+ isCCM8 = true;
+ break;
+
case SSL.ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case SSL.ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
case SSL.DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
inRec.SetDecryption(
new RecordDecryptCBC(block, hm, iv));
}
+ } else if (isCCM) {
+ /*
+ * CCM cipher suite.
+ */
+ if (write) {
+ outRec.SetEncryption(
+ new RecordEncryptCCM(block, iv, false));
+ } else {
+ inRec.SetDecryption(
+ new RecordDecryptCCM(block, iv, false));
+ }
+ } else if (isCCM8) {
+ /*
+ * CCM cipher suite with truncated MAC value.
+ */
+ if (write) {
+ outRec.SetEncryption(
+ new RecordEncryptCCM(block, iv, true));
+ } else {
+ inRec.SetDecryption(
+ new RecordDecryptCCM(block, iv, true));
+ }
} else if (block != null) {
/*
* GCM cipher suite.
"ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "ECDHE_ECDSA_WITH_AES_128_CCM",
+ "ECDHE_ECDSA_WITH_AES_256_CCM",
+ "ECDHE_ECDSA_WITH_AES_128_CCM_8",
+ "ECDHE_ECDSA_WITH_AES_256_CCM_8",
"ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"RSA_WITH_AES_128_GCM_SHA256",
"RSA_WITH_AES_256_GCM_SHA384",
+ "RSA_WITH_AES_128_CCM",
+ "RSA_WITH_AES_256_CCM",
+ "RSA_WITH_AES_128_CCM_8",
+ "RSA_WITH_AES_256_CCM_8",
"RSA_WITH_AES_128_CBC_SHA256",
"RSA_WITH_AES_256_CBC_SHA256",
"RSA_WITH_AES_128_CBC_SHA",