/// <summary> /// Encrypts a packet targeted to a single person /// </summary> /// <param name="packet">The packet to encrypt</param> /// <param name="targetPublicKey">Target's identity public key</param> /// <returns>Encrypted packet</returns> public static DEncodeValue EncryptTargetedPacket(DEncodeValue packet, byte[] targetPublicKey) { var targetCryptCsp = new RSACryptoServiceProvider(); targetCryptCsp.ImportCspBlob(targetPublicKey); var packetStream = new MemoryStream(); var writer = new DEncodeWriter(packetStream); writer.Write(packet); var packetBytes = packetStream.ToArray(); // create a unique packet key var csp = CreatePacketCryptingAlgoInstance(); var key = new byte[32]; var iv = new byte[32]; RngCsp.GetBytes(key); RngCsp.GetBytes(iv); csp.Key = key; csp.IV = iv; // encrypt the packet var cryptedPacketBytes = csp.CreateEncryptor().TransformFinalBlock(packetBytes, 0, packetBytes.Length); // now encrypt the packet key with the target's public key var encryptedKey = targetCryptCsp.Encrypt(key, true); var packetDict = new Dictionary<string, DEncodeValue>(); packetDict.Add("ty", new DEncodeString("targeted")); // type (encrypted, targeted packet) packetDict.Add("ke", new DEncodeArray(encryptedKey)); // packet encryption key (encrypted with target's public key) packetDict.Add("iv", new DEncodeArray(iv)); // IV for the packet encryption packetDict.Add("pa", new DEncodeArray(cryptedPacketBytes)); // wrapped payload packet return new DEncodeDictionary(packetDict); }
/// <summary> /// Encrypts a packet without any specific target (= targeting the whole chat session) using a master key /// </summary> /// <param name="packet">The packet to encrypt</param> /// <param name="masterKey">The master key to use for encryption</param> /// <returns>Encrypted packet</returns> public static DEncodeValue EncryptNonTargetedPacket(DEncodeValue packet, byte[] masterKey) { var packetStream = new MemoryStream(); var writer = new DEncodeWriter(packetStream); writer.Write(packet); var packetBytes = packetStream.ToArray(); // create a unique packet key var csp = CreatePacketCryptingAlgoInstance(); var iv = new byte[32]; RngCsp.GetBytes(iv); csp.Key = masterKey; csp.IV = iv; // encrypt the packet var cryptedPacketBytes = csp.CreateEncryptor().TransformFinalBlock(packetBytes, 0, packetBytes.Length); var packetDict = new Dictionary<string, DEncodeValue>(); packetDict.Add("ty", new DEncodeString("nontargeted")); // type (encrypted, targeted packet) packetDict.Add("iv", new DEncodeArray(iv)); // IV for the packet encryption packetDict.Add("pa", new DEncodeArray(cryptedPacketBytes)); // wrapped payload packet return new DEncodeDictionary(packetDict); }
/// <summary> /// Sends a Crype packet to the chatroom /// </summary> /// <param name="packet">Crype packet body</param> public void SendPacket(DEncodeValue packet) { var packetWriterStream = new MemoryStream(); var packetWriter = new DEncodeWriter(packetWriterStream); packetWriter.Write(packet); var messageToSend = Convert.ToBase64String(packetWriterStream.ToArray()); _chatImpl.SendMessage(messageToSend); }
/// <summary> /// Parses a packet decrypting it if necessary. Returns the unwrapped plain packet and information about the options of the packet /// </summary> /// <param name="packet">The packet</param> /// <param name="targetedDecryptorCsp">RSA instance to decrypt targeted packets</param> /// <param name="untargetedMasterKey">Master key to decrypt untargeted packets on chat</param> /// <returns>The unwrapped packet and information about it</returns> public static PacketInfo UnwrapPacket(DEncodeValue packet, RSACryptoServiceProvider targetedDecryptorCsp, byte[] untargetedMasterKey) { var packetDict = (DEncodeDictionary) packet; var type = ((DEncodeString) packetDict.Items["ty"]).Value; if (type == "plain") { return new PacketInfo(packet, false, null, false, false); } if (type == "sigwrap") { var signedByKey = ((DEncodeArray) packetDict.Items["sb"]).Value; var signature = ((DEncodeArray) packetDict.Items["si"]).Value; var wrappedPacket = packetDict.Items["pa"]; var packetStream = new MemoryStream(); var writer = new DEncodeWriter(packetStream); writer.Write(wrappedPacket); var wrappedPacketBytes = packetStream.ToArray(); var validatorCsp = new RSACryptoServiceProvider(); validatorCsp.ImportCspBlob(signedByKey); if (!validatorCsp.VerifyHash(ComputeSha1Hash(wrappedPacketBytes), Sha1Csp.ToString(), signature)) { throw new CryptographicException("Invalid signature"); } var wrappedPacketInfo = UnwrapPacket(wrappedPacket, targetedDecryptorCsp, untargetedMasterKey); wrappedPacketInfo.IsSigned = true; wrappedPacketInfo.SignedByKey = signedByKey; return wrappedPacketInfo; } if (type == "targeted") { var encryptedPacketKey = ((DEncodeArray) packetDict.Items["ke"]).Value; var iv = ((DEncodeArray) packetDict.Items["iv"]).Value; var encryptedPacketBytes = ((DEncodeArray) packetDict.Items["pa"]).Value; // decrypt the packet key var packetKey = targetedDecryptorCsp.Decrypt(encryptedPacketKey, true); // decrypt the packet var decryptorCsp = CreatePacketCryptingAlgoInstance(); decryptorCsp.Key = packetKey; decryptorCsp.IV = iv; var decryptedPacketBytes = decryptorCsp.CreateDecryptor() .TransformFinalBlock(encryptedPacketBytes, 0, encryptedPacketBytes.Length); // parse the wrapped packet var reader = new DEncodeReader(new MemoryStream(decryptedPacketBytes)); var wrappedPacket = reader.Read(); var wrappedPacketInfo = UnwrapPacket(wrappedPacket, targetedDecryptorCsp, untargetedMasterKey); wrappedPacketInfo.IsTargeted = true; return wrappedPacketInfo; } if (type == "nontargeted") { var iv = ((DEncodeArray)packetDict.Items["iv"]).Value; var encryptedPacketBytes = ((DEncodeArray)packetDict.Items["pa"]).Value; // decrypt the packet var decryptorCsp = CreatePacketCryptingAlgoInstance(); decryptorCsp.Key = untargetedMasterKey; decryptorCsp.IV = iv; var decryptedPacketBytes = decryptorCsp.CreateDecryptor() .TransformFinalBlock(encryptedPacketBytes, 0, encryptedPacketBytes.Length); // parse the wrapped packet var reader = new DEncodeReader(new MemoryStream(decryptedPacketBytes)); var wrappedPacket = reader.Read(); var wrappedPacketInfo = UnwrapPacket(wrappedPacket, targetedDecryptorCsp, untargetedMasterKey); wrappedPacketInfo.IsUntargeted = true; return wrappedPacketInfo; } throw new Exception("Invalid packet type code"); }
/// <summary> /// Signs a packet with RSA /// </summary> /// <param name="packet">The packet to sign</param> /// <param name="signingCsp">RSA instance with private key used to sign the packet</param> /// <returns>Signed packet</returns> public static DEncodeValue SignPacket(DEncodeValue packet, RSACryptoServiceProvider signingCsp) { var packetStream = new MemoryStream(); var writer = new DEncodeWriter(packetStream); writer.Write(packet); // sign the wrapped packet var packetBytes = packetStream.ToArray(); var packetHash = ComputeSha1Hash(packetBytes); var signature = signingCsp.SignHash(packetHash, Sha1Oid); // create a wrapper packet with the original packet inside it var packetDict = new Dictionary<string, DEncodeValue>(); packetDict.Add("ty", new DEncodeString("sigwrap")); // type (signature wrapper) packetDict.Add("sb", new DEncodeArray(signingCsp.ExportCspBlob(false))); // public key blob of the signer packetDict.Add("si", new DEncodeArray(signature)); // signature of payload packetDict.Add("pa", packet); // wrapped payload packet return new DEncodeDictionary(packetDict); }