/// <summary> /// Constuctor. /// </summary> /// <param name="operation">Specifies how the message should be interpreted.</param> /// <param name="timestamp">The time (UTC) when the delivery was completed successfully or was aborted.</param> /// <param name="targetEP">The original target or cluster endpoint.</param> /// <param name="confirmEP">The confirmation endpoint (or <c>null</c>).</param> /// <param name="query">The query message.</param> /// <param name="topologyID">The globally unique cluster topology provider instance ID or <see cref="Guid.Empty" />.</param> /// <param name="topologyInfo">The serialized cluster itopology nformation (or <c>null</c>).</param> /// <param name="topologyParam">The serialized topology parameter (or <c>null</c>).</param> /// <param name="exception">The exception for failed deliveries or queries.</param> /// <param name="response">The response message (or <c>null</c>).</param> public DeliveryMsg(DeliveryOperation operation, DateTime timestamp, MsgEP targetEP, MsgEP confirmEP, Msg query, Guid topologyID, string topologyInfo, string topologyParam, Exception exception, Msg response) { this.Operation = operation; this.Timestamp = timestamp; this.TargetEP = targetEP; this.ConfirmEP = confirmEP; this.TopologyID = topologyID; this.TopologyInfo = topologyInfo; this.TopologyParam = topologyParam; this.Exception = exception; this.query = query; this.response = response; // Serialize the query and responses to the message blob EnhancedBlockStream es = new EnhancedBlockStream(); try { Msg.Save(es, query); if (response != null) { Msg.Save(es, response); } base._Data = es.ToArray(); } finally { es.Close(); } }
public void EnhancedBlockStream_ToByteArray() { var es = new EnhancedBlockStream(); byte[] buf; es.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 0, 10); buf = es.ToArray(); CollectionAssert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, buf); buf[0] = 255; es.Position = 0; Assert.AreEqual(0, es.ReadByte()); }
/// <summary> /// Renders the packet into a form suitable for transmission via UDP. /// </summary> /// <returns>The raw packet byte array.</returns> public byte[] ToArray() { var bs = new EnhancedBlockStream(0, 2048); bs.WriteByte((byte)this.Code); bs.WriteByte((byte)this.Identifier); bs.WriteInt16(0); // Put a zero in for the length and come back and fill // this in after we know what the actual length is. bs.WriteBytesNoLen(this.Authenticator); for (int i = 0; i < this.Attributes.Count; i++) { var attr = this.Attributes[i]; if (attr.Value.Length > RadiusAttribute.MaxValueLen) { throw new RadiusException("Attribute value size exceeds 253 bytes."); } bs.WriteByte((byte)attr.Type); bs.WriteByte((byte)(attr.Value.Length + 2)); bs.WriteBytesNoLen(attr.Value); } // Go back and write the actual length if (bs.Length > short.MaxValue) { throw new RadiusException("RADIUS packet is too large."); } bs.Position = 2; bs.WriteInt16((int)bs.Length); return(bs.ToArray()); }
/// <summary> /// Decrypts a user password by encrypted using <see cref="EncryptUserPassword" /> /// using the message authenticator and the shared NAS secret. /// </summary> /// <param name="encryptedPassword">The encrypted password.</param> /// <param name="secret">The shared NAS secret.</param> /// <returns>The decrypted password.</returns> /// <exception cref="RadiusException">Thrown if the encrypted password is invalid.</exception> public string DecryptUserPassword(byte[] encryptedPassword, string secret) { var bs = new EnhancedBlockStream(128, 128); byte[] secretBytes = Helper.ToAnsi(secret); byte[] clearBlock = new byte[16]; byte[] xorHash; byte[] decrypted; int pos; int zeroPos; try { // The encrypted password length must be a non-zero multiple of 16 bytes. if (encryptedPassword.Length == 0 || encryptedPassword.Length % 16 != 0) { throw new RadiusException("Encrypted user password length must be a positive multiple of 16 bytes."); } // The first XOR hash is MD5(secret + authenticator) xorHash = MD5Hasher.Compute(Helper.Concat(secretBytes, this.Authenticator)); // Perform the decryption. The trick here is to unmunge the 16 byte // blocks by XORing them with the current XOR hash. pos = 0; while (true) { // clearBlock = XOR hash ^ next 16 encrypted bytes for (int i = 0; i < 16; i++) { clearBlock[i] = (byte)(xorHash[i] ^ encryptedPassword[pos + i]); } bs.WriteBytesNoLen(clearBlock); pos += 16; if (pos >= encryptedPassword.Length) { break; } // Next XOR hash = MD5(secret + last cypherblock) xorHash = MD5Hasher.Compute(Helper.Concat(secretBytes, Helper.Extract(encryptedPassword, pos - 16, 16))); } // Scan forward to the first zero byte. If we find one, we're going // to assume that it was a padding byte. decrypted = bs.ToArray(); zeroPos = -1; for (int i = 0; i < decrypted.Length; i++) { if (decrypted[i] == 0) { zeroPos = i; break; } } if (zeroPos == -1) { return(Helper.FromAnsi(decrypted)); } else { return(Helper.FromAnsi(decrypted, 0, zeroPos)); } } finally { bs.Close(); } }
/// <summary> /// Encrypts a user password string by combining it with the shared NAS /// secret and the message authenticator as described in RFC 2865 page 27. /// </summary> /// <param name="userPassword">The user password to be encrypted.</param> /// <param name="secret">The shared NAS secret.</param> /// <returns>The encrypted password.</returns> /// <exception cref="RadiusException">Thrown if the password is too large or too small.</exception> public byte[] EncryptUserPassword(string userPassword, string secret) { var bs = new EnhancedBlockStream(128, 128); byte[] secretBytes = Helper.ToAnsi(secret); byte[] cypherBlock = new byte[16]; byte[] rawPwd; byte[] xorHash; byte[] pwd; int pos; try { rawPwd = Helper.ToAnsi(userPassword); if (rawPwd.Length == 0) { throw new RadiusException("Zero length password is not allowed."); } // Copy userPassword into pwd, padding the result out with zeros // to a multiple of 16 bytes if (rawPwd.Length % 16 == 0) { pwd = rawPwd; } else { pwd = new byte[(rawPwd.Length / 16 + 1) * 16]; Array.Copy(rawPwd, pwd, rawPwd.Length); } // The first XOR hash is MD5(secret + authenticator) xorHash = MD5Hasher.Compute(Helper.Concat(secretBytes, this.Authenticator)); // Perform the encryption pos = 0; while (true) { // Cyperblock = XOR hash ^ next 16 bytes of password for (int i = 0; i < 16; i++) { cypherBlock[i] = (byte)(xorHash[i] ^ pwd[pos + i]); } bs.WriteBytesNoLen(cypherBlock); pos += 16; if (pos >= pwd.Length) { break; } // Next XOR hash is MD5(secret + cypherblock) xorHash = MD5Hasher.Compute(Helper.Concat(secretBytes, cypherBlock)); } if (bs.Length > 128) { throw new RadiusException("Encrypted password exceeds 128 bytes."); } return(bs.ToArray()); } finally { bs.Close(); } }