private void AES_CCM(byte[] k) { CcmBlockCipher cipher = new CcmBlockCipher(new AesEngine()); KeyParameter contentKey; int cbitTag = 64; // The requirements from JWA // IV is 96 bits // Authentication tag is 128 bits // key sizes are 128, 192 and 256 bits _iv = new byte[96 / 8]; s_PRNG.NextBytes(_iv); contentKey = new KeyParameter(k); // Build the object to be hashed byte[] a = new byte[0]; if (ProtectedMap != null) { a = Encoding.UTF8.GetBytes(ProtectedMap.ToString()); } AeadParameters parameters = new AeadParameters(contentKey, 128, _iv, a); cipher.Init(true, parameters); byte[] c = new byte[cipher.GetOutputSize(payload.Length)]; int len = cipher.ProcessBytes(payload, 0, payload.Length, c, 0); cipher.DoFinal(c, len); Array.Resize(ref c, c.Length - (128 / 8) + (cbitTag / 8)); _RgbEncrypted = c; }
/// <summary> /// Encrypt the message based on attributes and recipients. /// </summary> public virtual void Encrypt() { string alg = null; // Get the algorithm we are using - the default is AES GCM try { alg = FindAttribute("enc").AsString(); } catch { foreach (Recipient r in RecipientList) { CBORObject alg2 = r.FindAttribute("enc"); if (alg2 != null) { if (alg2.Type != CBORType.TextString || (alg != null && alg != alg2.AsString())) { throw new JoseException("Multiple content encryption algorithms have been specified."); } alg = alg2.AsString(); } } if (alg == null) { throw new JoseException("Content encryption algorithm has not been specified."); } } byte[] contentKey = null; // Determine if we are doing a direct encryption int recipientTypes = 0; if (RecipientList.Count == 0) { throw new JoseException("Must have at least one recipient for the message"); } foreach (Recipient key in RecipientList) { switch (key.RecipientType) { case RecipientType.Direct: case RecipientType.KeyAgreeDirect: if ((recipientTypes & 1) != 0) { throw new JoseException("It is not legal to have two direct recipients in a message"); } recipientTypes |= 1; contentKey = key.GetKey(alg, this); break; default: recipientTypes |= 2; break; } } if (recipientTypes == 3) { throw new JoseException("It is not legal to mix direct and indirect recipients in a message"); } if (contentKey == null) { switch (alg) { case "A128GCM": case "AES-128-CCM-64": contentKey = new byte[128 / 8]; break; case "A192GCM": case "AES192GCM": contentKey = new byte[192 / 8]; break; case "A256GCM": case "AES256GCM": contentKey = new byte[256 / 8]; break; case "A128CBC-HS256": contentKey = new byte[2 * 128 / 8]; break; case "A192CBC-HS256": contentKey = new byte[2 * 192 / 8]; break; case "A256CBC-HS256": contentKey = new byte[2 * 256 / 8]; break; default: throw new JoseException($"Unrecognized content encryption algorithm '{alg}'"); } s_PRNG.NextBytes(contentKey); } foreach (Recipient key in RecipientList) { key.SetContent(contentKey); key.Encrypt(this); } // Encode the protected attributes if there are any if (ProtectedMap.Count > 0) { _strProtected = base64urlencode(Encoding.UTF8.GetBytes(ProtectedMap.ToString())); } byte[] saveContent = payload; if (ProtectedMap.ContainsKey("zip")) { MemoryStream stm2 = new MemoryStream(); DeflateStream zipStm = new DeflateStream(stm2, CompressionMode.Compress); zipStm.Write(payload, 0, payload.Length); zipStm.Close(); payload = stm2.GetBuffer(); } switch (alg) { case "A128GCM": case "A192GCM": case "A256GCM": AES_GCM_Encrypt(contentKey); break; case "AES-128-CCM-64": AES_CCM(contentKey); break; case "A128CBC-HS256": case "A192CBC-HS256": case "A256CBC-HS256": AES_CBC_MAC_Encrypt(alg, contentKey); break; default: throw new JoseException("Internal Error: We should never get here."); } payload = saveContent; }
/// <inheritdoc /> protected override CBORObject InternalEncodeToJSON(bool fCompact) { CBORObject obj = CBORObject.NewMap(); if (_RgbEncrypted == null) { Encrypt(); } if (ProtectedMap.Count > 0) { obj.Add("protected", base64urlencode(Encoding.UTF8.GetBytes(ProtectedMap.ToString()))); } if (UnprotectedMap.Count > 0) { obj.Add("unprotected", UnprotectedMap); // Add unprotected attributes } if (_iv != null) { obj.Add("iv", base64urlencode(_iv)); // Add iv } if (_Aad != null) { obj.Add("aad", Encoding.UTF8.GetString(_Aad)); } if (_RgbEncrypted != null) { obj.Add("ciphertext", base64urlencode(_RgbEncrypted)); // Add ciphertext } obj.Add("tag", base64urlencode(_Tag)); if (RecipientList.Count > 0) { CBORObject recipients = CBORObject.NewArray(); foreach (Recipient key in RecipientList) { CBORObject j = key.EncodeToJSON(); if ((j != null) && (j.Count != 0)) { recipients.Add(j); } } if (fCompact) { if (recipients.Count != 1) { throw new JoseException("Compact encoding must be for one recipient"); } if (recipients[0].ContainsKey("encrypted_key")) { obj.Add("encrypted_key", recipients[0]["encrypted_key"]); } if (recipients[0].ContainsKey("header")) { obj.Add("header", recipients[0]["header"]); } } else { if (recipients.Count > 0) { obj.Add("recipients", recipients); } } } else { throw new JoseException("Must have one or more recipients"); } return(obj); }