/** * instead of a password, it's also possible to decrypt via certificate. * Warning: this code is experimental and hasn't been validated * * @see <a href="http://social.msdn.microsoft.com/Forums/en-US/cc9092bb-0c82-4b5b-ae21-abf643bdb37c/agile-encryption-with-certificates">Agile encryption with certificates</a> * * @param keyPair * @param x509 * @return true, when the data can be successfully decrypted with the given private key * @throws GeneralSecurityException */ public bool VerifyPassword(KeyPair keyPair, X509Certificate x509) { AgileEncryptionVerifier ver = (AgileEncryptionVerifier)builder.GetVerifier(); AgileEncryptionHeader header = (AgileEncryptionHeader)builder.GetHeader(); HashAlgorithm hashAlgo = header.HashAlgorithm; CipherAlgorithm cipherAlgo = header.CipherAlgorithm; int blockSize = header.BlockSize; AgileCertificateEntry ace = null; foreach (AgileCertificateEntry aceEntry in ver.GetCertificates()) { if (x509.Equals(aceEntry.x509)) { ace = aceEntry; break; } } if (ace == null) { return(false); } Cipher cipher = Cipher.GetInstance("RSA"); cipher.Init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); byte[] keyspec = cipher.DoFinal(ace.encryptedKey); SecretKeySpec secretKey = new SecretKeySpec(keyspec, ver.CipherAlgorithm.jceId); Mac x509Hmac = CryptoFunctions.GetMac(hashAlgo); x509Hmac.Init(secretKey); byte[] certVerifier = x509Hmac.DoFinal(ace.x509.GetEncoded()); byte[] vec = CryptoFunctions.GenerateIv(hashAlgo, header.KeySalt, kIntegrityKeyBlock, blockSize); cipher = GetCipher(secretKey, cipherAlgo, ver.ChainingMode, vec, Cipher.DECRYPT_MODE); byte[] hmacKey = cipher.DoFinal(header.GetEncryptedHmacKey()); hmacKey = GetBlock0(hmacKey, hashAlgo.hashSize); vec = CryptoFunctions.GenerateIv(hashAlgo, header.KeySalt, kIntegrityValueBlock, blockSize); cipher = GetCipher(secretKey, cipherAlgo, ver.ChainingMode, vec, Cipher.DECRYPT_MODE); byte[] hmacValue = cipher.DoFinal(header.GetEncryptedHmacValue()); hmacValue = GetBlock0(hmacValue, hashAlgo.hashSize); if (Arrays.Equals(ace.certVerifier, certVerifier)) { SetSecretKey(secretKey); SetIntegrityHmacKey(hmacKey); SetIntegrityHmacValue(hmacValue); return(true); } else { return(false); } }
/// <exception cref="System.IO.IOException"></exception> private void Authorize(HttpURLConnection c) { IDictionary <string, IList <string> > reqHdr = c.GetRequestProperties(); SortedDictionary <string, string> sigHdr = new SortedDictionary <string, string>(); foreach (KeyValuePair <string, IList <string> > entry in reqHdr.EntrySet()) { string hdr = entry.Key; if (IsSignedHeader(hdr)) { sigHdr.Put(StringUtils.ToLowerCase(hdr), ToCleanString(entry.Value)); } } StringBuilder s = new StringBuilder(); s.Append(c.GetRequestMethod()); s.Append('\n'); s.Append(Remove(sigHdr, "content-md5")); s.Append('\n'); s.Append(Remove(sigHdr, "content-type")); s.Append('\n'); s.Append(Remove(sigHdr, "date")); s.Append('\n'); foreach (KeyValuePair <string, string> e in sigHdr.EntrySet()) { s.Append(e.Key); s.Append(':'); s.Append(e.Value); s.Append('\n'); } string host = c.GetURL().GetHost(); s.Append('/'); s.Append(Sharpen.Runtime.Substring(host, 0, host.Length - DOMAIN.Length - 1)); s.Append(c.GetURL().AbsolutePath); string sec; try { Mac m = Mac.GetInstance(HMAC); m.Init(privateKey); sec = Base64.EncodeBytes(m.DoFinal(Sharpen.Runtime.GetBytesForString(s.ToString() , "UTF-8"))); } catch (NoSuchAlgorithmException e_1) { throw new IOException(MessageFormat.Format(JGitText.Get().noHMACsupport, HMAC, e_1 .Message)); } catch (InvalidKeyException e_1) { throw new IOException(MessageFormat.Format(JGitText.Get().invalidKey, e_1.Message )); } c.SetRequestProperty("Authorization", "AWS " + publicKey + ":" + sec); }
public virtual void DoFinal(byte[] buf, int offset) { try { mac.DoFinal(buf, offset); } catch (ShortBufferException) { } }
public virtual void DoFinal(byte[] buf, int offset) { try { mac.DoFinal(_buf16, 0); } catch (ShortBufferException) { } System.Array.Copy(_buf16, 0, buf, offset, 12); }
/// <summary> /// Compute HMAC of the identifier using the secret key and return the /// output as password /// </summary> /// <param name="identifier">the bytes of the identifier</param> /// <param name="key">the secret key</param> /// <returns>the bytes of the generated password</returns> protected internal static byte[] CreatePassword(byte[] identifier, SecretKey key) { Mac mac = threadLocalMac.Get(); try { mac.Init(key); } catch (InvalidKeyException ike) { throw new ArgumentException("Invalid key to HMAC computation", ike); } return(mac.DoFinal(identifier)); }
protected override byte[] DecryptBlock( byte[] inEnc, int inOff, int inLen) { // Ensure that the length of the input is greater than the MAC in bytes if (inLen < (V.Length + Mac.GetMacSize())) { throw new InvalidCipherTextException("Length of input must be greater than the MAC and V combined"); } // note order is important: set up keys, do simple encryption, check mac, do final encryption. if (Cipher == null) { // Streaming mode. throw new ArgumentNullException(string.Format("{0}", "Cipher Cannot be Null in This Mode.")); } // Block cipher mode. SetupBlockCipherAndMacKeyBytes(out byte[] k1, out byte[] k2); ICipherParameters cp = new KeyParameter(k1); // If IV provide use it to initialize the cipher if (Iv != null) { cp = new ParametersWithIV(cp, Iv); } Cipher.Init(false, cp); // Verify the MAC. byte[] t1 = new byte[Mac.GetMacSize()]; Array.Copy(inEnc, V.Length, t1, 0, t1.Length); byte[] t2 = new byte[t1.Length]; Mac.Init(new KeyParameter(k2)); Mac.BlockUpdate(inEnc, inOff + V.Length + t2.Length, inLen - V.Length - t2.Length); Mac.DoFinal(t2, 0); if (!Arrays.ConstantTimeAreEqual(t1, t2)) { throw new InvalidCipherTextException("invalid MAC"); } return(Cipher.DoFinal(inEnc, inOff + V.Length + Mac.GetMacSize(), inLen - V.Length - t2.Length)); }
/** * Example code from http://msdn.microsoft.com/library/azure/dn495627.aspx to * construct a SaS token from the access key to authenticate a request. * * @param uri The unencoded resource URI string for this operation. The resource * URI is the full URI of the Service Bus resource to which access is * claimed. For example, * "http://<namespace>.servicebus.windows.net/<hubName>" */ private static String GenerateSasToken(String uri) { String targetUri; String token = null; try { targetUri = new String(URLEncoder .Encode(uri.ToString().ToLower(), "UTF-8") .ToLower()); long expiresOnDate = JavaSystem.CurrentTimeMillis(); int expiresInMins = 60; // 1 hour expiresOnDate += expiresInMins * 60 * 1000; long expires = expiresOnDate / 1000; String toSign = new String(targetUri + "\n" + expires); // Get an hmac_sha1 key from the raw key bytes byte[] keyBytes = HubSasKeyValue.GetBytes("UTF-8"); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); // Get an hmac_sha1 Mac instance and initialize with the signing key Mac mac = Mac.GetInstance("HmacSHA256"); mac.Init(signingKey); // Compute the hmac on input data bytes byte[] rawHmac = mac.DoFinal(toSign.GetBytes("UTF-8")); // Using android.util.Base64 for Android Studio instead of // Apache commons codec String signature = new String(URLEncoder.Encode( Base64.EncodeToString(rawHmac, Base64Flags.NoWrap).ToString(), "UTF-8")); // Construct authorization string token = new String("SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires + "&skn=" + HubSasKeyName); } catch (Exception e) { MainActivity.CurrentActivity.ToastNotify("Exception Generating SaS : " + e.Message.ToString()); //if (isVisible) //{ // ToastNotify("Exception Generating SaS : " + e.getMessage().toString()); //} } return(token); }
/** * Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message), * which the DataIntegrity element will verify by using the Salt generated in step 2 as the key. * Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be * used as the message. * * Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes: * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33. **/ protected void UpdateIntegrityHMAC(FileInfo tmpFile, int oleStreamSize) { // as the integrity hmac needs to contain the StreamSize, // it's not possible to calculate it on-the-fly while buffering // TODO: add stream size parameter to GetDataStream() AgileEncryptionVerifier ver = builder.GetVerifier(); HashAlgorithm hashAlgo = ver.HashAlgorithm; Mac integrityMD = CryptoFunctions.GetMac(hashAlgo); integrityMD.Init(new SecretKeySpec(integritySalt, hashAlgo.jceHmacId)); byte[] buf = new byte[1024]; LittleEndian.PutLong(buf, 0, oleStreamSize); integrityMD.Update(buf, 0, LittleEndian.LONG_SIZE); FileStream fis = tmpFile.Create(); try { int readBytes; while ((readBytes = fis.Read(buf, 0, buf.Length)) > 0) { integrityMD.Update(buf, 0, readBytes); } } finally { fis.Close(); } byte[] hmacValue = integrityMD.DoFinal(); AgileEncryptionHeader header = builder.GetHeader(); int blockSize = header.BlockSize; byte[] iv = CryptoFunctions.GenerateIv(header.HashAlgorithm, header.KeySalt, AgileDecryptor.kIntegrityValueBlock, blockSize); Cipher cipher = CryptoFunctions.GetCipher(GetSecretKey(), header.CipherAlgorithm, header.ChainingMode, iv, Cipher.ENCRYPT_MODE); byte[] hmacValueFilled = GetBlock0(hmacValue, AgileDecryptor.GetNextBlockSize(hmacValue.Length, blockSize)); byte[] encryptedHmacValue = cipher.DoFinal(hmacValueFilled); header.SetEncryptedHmacValue(encryptedHmacValue); }
private byte[] DecryptBlock( byte[] inEnc, int inOff, int inLen, byte[] macData) { byte[] M = null, K = null, K1 = null, K2 = null; int len; // Ensure that the length of the input is greater than the MAC in bytes if (inLen <= _iesParameters.MacKeySize / 8) { throw new InvalidCipherTextException("Length of input must be greater than the MAC"); } if (Cipher == null) { // Streaming mode. K1 = new byte[inLen - V.Length - Mac.GetMacSize()]; K2 = new byte[_iesParameters.MacKeySize / 8]; K = new byte[K1.Length + K2.Length]; _kdf.GenerateBytes(K, 0, K.Length); // if (V.Length != 0) // { // Array.Copy(K, 0, K2, 0, K2.Length); // Array.Copy(K, K2.Length, K1, 0, K1.Length); // } // else { Array.Copy(K, 0, K1, 0, K1.Length); Array.Copy(K, K1.Length, K2, 0, K2.Length); } M = new byte[K1.Length]; for (int i = 0; i != K1.Length; i++) { M[i] = (byte)(inEnc[inOff + V.Length + i] ^ K1[i]); } len = K1.Length; } else { // Block cipher mode. K1 = new byte[((IesWithCipherParameters)_iesParameters).CipherKeySize / 8]; K2 = new byte[_iesParameters.MacKeySize / 8]; K = new byte[K1.Length + K2.Length]; _kdf.GenerateBytes(K, 0, K.Length); Array.Copy(K, 0, K1, 0, K1.Length); Array.Copy(K, K1.Length, K2, 0, K2.Length); // If IV provide use it to initialize the cipher if (_iv != null) { Cipher.Init(false, new ParametersWithIV(new KeyParameter(K1), _iv)); } else { Cipher.Init(false, new KeyParameter(K1)); } M = new byte[Cipher.GetOutputSize(inLen - V.Length - Mac.GetMacSize())]; len = Cipher.ProcessBytes(inEnc, inOff + V.Length, inLen - V.Length - Mac.GetMacSize(), M, 0); len += Cipher.DoFinal(M, len); } // Convert the length of the encoding vector into a byte array. byte[] p2 = _iesParameters.GetEncodingV(); // Verify the MAC. int end = inOff + inLen; byte[] t1 = Arrays.CopyOfRange(inEnc, end - Mac.GetMacSize(), end); byte[] t2 = new byte[t1.Length]; byte[] k2A; if (HashK2) { k2A = new byte[_hash.GetDigestSize()]; _hash.Reset(); _hash.BlockUpdate(K2, 0, K2.Length); _hash.DoFinal(k2A, 0); } else { k2A = K2; } Mac.Init(new KeyParameter(k2A)); Mac.BlockUpdate(_iv, 0, _iv.Length); Mac.BlockUpdate(inEnc, inOff + V.Length, inLen - V.Length - t2.Length); if (p2 != null) { Mac.BlockUpdate(p2, 0, p2.Length); } if (V.Length != 0 && p2 != null) { // byte[] L2 = new byte[4]; // Pack.intToBigEndian(P2.Length * 8, L2, 0); byte[] L2 = (p2.Length * 8).ToBigEndianByteArray(); Debug.Assert(L2.Length == 4, "expected to be 4 bytes long"); Mac.BlockUpdate(L2, 0, L2.Length); } if (macData != null) { Mac.BlockUpdate(macData, 0, macData.Length); } Mac.DoFinal(t2, 0); if (!Arrays.ConstantTimeAreEqual(t1, t2)) { throw new InvalidCipherTextException("Invalid MAC."); } // Output the message. return(Arrays.CopyOfRange(M, 0, len)); }
private byte[] EncryptBlock( byte[] input, int inOff, int inLen, byte[] macData) { byte[] c, k, k1, k2; int len; if (Cipher == null) { // Streaming mode. k1 = new byte[inLen]; k2 = new byte[_iesParameters.MacKeySize / 8]; k = new byte[k1.Length + k2.Length]; _kdf.GenerateBytes(k, 0, k.Length); // if (V.Length != 0) // { // Array.Copy(K, 0, K2, 0, K2.Length); // Array.Copy(K, K2.Length, K1, 0, K1.Length); // } // else { Array.Copy(k, 0, k1, 0, k1.Length); Array.Copy(k, inLen, k2, 0, k2.Length); } c = new byte[inLen]; for (int i = 0; i != inLen; i++) { c[i] = (byte)(input[inOff + i] ^ k1[i]); } len = inLen; } else { // Block cipher mode. k1 = new byte[((IesWithCipherParameters)_iesParameters).CipherKeySize / 8]; k2 = new byte[_iesParameters.MacKeySize / 8]; k = new byte[k1.Length + k2.Length]; _kdf.GenerateBytes(k, 0, k.Length); Array.Copy(k, 0, k1, 0, k1.Length); Array.Copy(k, k1.Length, k2, 0, k2.Length); // If iv provided use it to initialise the cipher if (_iv != null) { Cipher.Init(true, new ParametersWithIV(new KeyParameter(k1), _iv)); } else { Cipher.Init(true, new KeyParameter(k1)); } c = new byte[Cipher.GetOutputSize(inLen)]; len = Cipher.ProcessBytes(input, inOff, inLen, c, 0); len += Cipher.DoFinal(c, len); } // Convert the length of the encoding vector into a byte array. byte[] p2 = _iesParameters.GetEncodingV(); // Apply the MAC. byte[] T = new byte[Mac.GetMacSize()]; byte[] k2A; if (HashK2) { k2A = new byte[_hash.GetDigestSize()]; _hash.Reset(); _hash.BlockUpdate(k2, 0, k2.Length); _hash.DoFinal(k2A, 0); } else { k2A = k2; } Mac.Init(new KeyParameter(k2A)); Mac.BlockUpdate(_iv, 0, _iv.Length); Mac.BlockUpdate(c, 0, c.Length); if (p2 != null) { Mac.BlockUpdate(p2, 0, p2.Length); } if (V.Length != 0 && p2 != null) { // byte[] L2 = new byte[4]; // Pack.intToBigEndian(P2.Length * 8, L2, 0); byte[] L2 = (p2.Length * 8).ToBigEndianByteArray(); Debug.Assert(L2.Length == 4, "expected to be 4 bytes long"); Mac.BlockUpdate(L2, 0, L2.Length); } if (macData != null) { Mac.BlockUpdate(macData, 0, macData.Length); } Mac.DoFinal(T, 0); // Output the triple (V,C,T). byte[] Output = new byte[V.Length + len + T.Length]; Array.Copy(V, 0, Output, 0, V.Length); Array.Copy(c, 0, Output, V.Length, len); Array.Copy(T, 0, Output, V.Length + len, T.Length); return(Output); }
public override void ConfirmPassword(String password, byte[] keySpec, byte[] keySalt, byte[] verifier, byte[] verifierSalt, byte[] integritySalt) { AgileEncryptionVerifier ver = builder.GetVerifier(); ver.Salt = (/*setter*/ verifierSalt); AgileEncryptionHeader header = builder.GetHeader(); header.KeySalt = (/*setter*/ keySalt); HashAlgorithm hashAlgo = ver.HashAlgorithm; int blockSize = header.BlockSize; pwHash = HashPassword(password, hashAlgo, verifierSalt, ver.SpinCount); /** * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps: * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize * attribute. * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password, * the binary byte array used to create the saltValue attribute, and a blockKey byte array * consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79. * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue * attribute as an Initialization vector as specified in section 2.3.4.12. If the array of bytes is not an * integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of * blockSize bytes. * 4. Use base64 to encode the result of step 3. */ byte[] encryptedVerifier = AgileDecryptor.hashInput(builder, pwHash, AgileDecryptor.kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE); ver.EncryptedVerifier = (/*setter*/ encryptedVerifier); /** * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps: * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for * encryptedVerifierHashInput. * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password, * the binary byte array used to create the saltValue attribute, and a blockKey byte array * consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e. * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as * an Initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of * blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes. * 4. Use base64 to encode the result of step 3. */ MessageDigest hashMD = GetMessageDigest(hashAlgo); byte[] hashedVerifier = hashMD.Digest(verifier); byte[] encryptedVerifierHash = AgileDecryptor.hashInput(builder, pwHash, AgileDecryptor.kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE); ver.EncryptedVerifierHash = (/*setter*/ encryptedVerifierHash); /** * encryptedKeyValue: This attribute MUST be generated by using the following steps: * 1. Generate a random array of bytes that is the same size as specified by the * Encryptor.KeyData.keyBits attribute of the parent element. * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password, * the binary byte array used to create the saltValue attribute, and a blockKey byte array * consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6. * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue * attribute as an Initialization vector as specified in section 2.3.4.12. If the array of bytes is not an * integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of * blockSize bytes. * 4. Use base64 to encode the result of step 3. */ byte[] encryptedKey = AgileDecryptor.hashInput(builder, pwHash, AgileDecryptor.kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE); ver.EncryptedKey = (/*setter*/ encryptedKey); ISecretKey secretKey = new SecretKeySpec(keySpec, ver.CipherAlgorithm.jceId); SetSecretKey(secretKey); /* * 2.3.4.14 DataIntegrity Generation (Agile Encryption) * * The DataIntegrity element Contained within an Encryption element MUST be generated by using * the following steps: * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor * Contained within the KeyEncryptors sequence. Use this key for encryption operations in the * remaining steps of this section. * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the * KeyData.HashSize attribute. * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the * KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes: * 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an Initialization vector as * specified in section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize * bytes, pad the array with 0x00 to the next integral multiple of blockSize bytes. * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3. * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message), * which the DataIntegrity element will verify by using the Salt generated in step 2 as the key. * Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be * used as the message. * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes: * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33. * 7. Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6. */ this.integritySalt = integritySalt; try { byte[] vec = CryptoFunctions.GenerateIv(hashAlgo, header.KeySalt, AgileDecryptor.kIntegrityKeyBlock, header.BlockSize); Cipher cipher = GetCipher(secretKey, ver.CipherAlgorithm, ver.ChainingMode, vec, Cipher.ENCRYPT_MODE); byte[] FilledSalt = GetBlock0(integritySalt, AgileDecryptor.GetNextBlockSize(integritySalt.Length, blockSize)); byte[] encryptedHmacKey = cipher.DoFinal(FilledSalt); header.SetEncryptedHmacKey(encryptedHmacKey); cipher = Cipher.GetInstance("RSA"); foreach (AgileCertificateEntry ace in ver.GetCertificates()) { cipher.Init(Cipher.ENCRYPT_MODE, ace.x509.GetPublicKey()); ace.encryptedKey = cipher.DoFinal(GetSecretKey().GetEncoded()); Mac x509Hmac = CryptoFunctions.GetMac(hashAlgo); x509Hmac.Init(GetSecretKey()); ace.certVerifier = x509Hmac.DoFinal(ace.x509.GetEncoded()); } } catch (Exception e) { throw new EncryptedDocumentException(e); } }
protected override unsafe byte[] EncryptBlock( byte[] @in, int inOff, int inLen) { if (Cipher == null) { // Streaming mode. throw new ArgumentNullException(string.Format("{0}", "Cipher Cannot be Null in This Mode.")); } // Block cipher mode. SetupBlockCipherAndMacKeyBytes(out byte[] k1, out byte[] k2); // If iv provided use it to initialise the cipher if (Iv != null) { Cipher.Init(true, new ParametersWithIV(new KeyParameter(k1), Iv)); } else { Cipher.Init(true, new KeyParameter(k1)); } byte[] c = Cipher.DoFinal(@in, inOff, inLen); // Apply the MAC. byte[] T = new byte[Mac.GetMacSize()]; Mac.Init(new KeyParameter(k2)); Mac.BlockUpdate(c, 0, c.Length); Mac.DoFinal(T, 0); int cipherBlockSize = Cipher.GetBlockSize(); int messageToEncryptSize = inLen - inOff; int messageToEncryptPadSize = (messageToEncryptSize % cipherBlockSize) == 0 ? 0 : cipherBlockSize - (messageToEncryptSize % cipherBlockSize); // Output the quadruple (SECURE_HEAD_DETAILS,V,T,C). // SECURE_HEAD_DETAILS := // [0] := Convert Byte(Length(V)) to a ByteArray, // [1] := Convert Byte(Length(T)) to a ByteArray, // [2] and [3] := Convert UInt16(MessageToEncryptSize) to a ByteArray, // [4] and [5] := Convert UInt16(MessageToEncryptSize + MessageToEncryptPadSize) to a ByteArray, // V := Ephemeral Public Key // T := Authentication Message (MAC) // C := Encrypted Payload byte[] output = new byte[SecureHeadSize + V.Length + T.Length + c.Length]; fixed(byte *ptrByteOutput = output) { ushort *ptrUShortOutput = (ushort *)ptrByteOutput; *ptrByteOutput = (byte)(V.Length); *(ptrByteOutput + 1) = (byte)(T.Length); *(ptrUShortOutput + 1) = (ushort)(messageToEncryptSize); *(ptrUShortOutput + 2) = (ushort)(messageToEncryptSize + messageToEncryptPadSize); } Array.Copy(V, 0, output, SecureHeadSize, V.Length); Array.Copy(T, 0, output, SecureHeadSize + V.Length, T.Length); Array.Copy(c, 0, output, SecureHeadSize + V.Length + T.Length, c.Length); return(output); }