public void EnhancedBlockStream_Bytes32() { var es = new EnhancedBlockStream(); byte[] read, write; es.WriteBytes32(null); es.Seek(0, SeekOrigin.Begin); read = es.ReadBytes32(); Assert.IsNull(read); write = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; es.Seek(0, SeekOrigin.Begin); es.WriteBytes32(write); es.Seek(0, SeekOrigin.Begin); read = es.ReadBytes32(); CollectionAssert.AreEqual(write, read); write = new byte[40000]; for (int i = 0; i < write.Length; i++) { write[i] = (byte)i; } es.Seek(0, SeekOrigin.Begin); es.WriteBytes32(write); es.Seek(0, SeekOrigin.Begin); read = es.ReadBytes32(); CollectionAssert.AreEqual(write, read); }
/// <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(); } }
/// <summary> /// Handles the deserialization of the <see cref="Query" /> and <see cref="Response" /> /// messages from the blob data. /// </summary> /// <param name="es">The enhanced stream holding the payload data.</param> protected override void ReadFrom(EnhancedStream es) { // Let the base message class load the properties and the data blob. base.ReadFrom(es); // Now parse the query and (optional) response messages from the blob es = new EnhancedBlockStream(base._Data); try { query = Msg.Load(es); if (es.Eof) { response = null; } else { response = Msg.Load(es); } } finally { es.Close(); } }
/// <summary> /// Uses the HMAC/SHA256 algorithm to hash data from a buffer and returns the result. /// </summary> /// <param name="key">The secret key.</param> /// <param name="data">The input buffer.</param> /// <param name="pos">Index of the first byte to be hashed.</param> /// <param name="length">The number of bytes to hash.</param> /// <returns>The hashed digest.</returns> public static byte[] Compute(byte[] key, byte[] data, int pos, int length) { byte[] xorBuf = new byte[64]; byte[] hash; EnhancedBlockStream es; // If the key length is greater than 64 bytes then hash the key // first to get it down to a reasonable size. if (key.Length > 64) { key = Compute(key); } // Pad the key with zeros to 64 bytes in length. if (key.Length < 64) { byte[] newKey = new byte[64]; for (int i = 0; i < newKey.Length; i++) { if (i < key.Length) { newKey[i] = key[i]; } else { newKey[i] = 0; } } key = newKey; } // XOR the key with iPad and put the result in xorBuf for (int i = 0; i < 64; i++) { xorBuf[i] = (byte)(key[i] ^ iPad); } // Hash the result of the data appended to xorBuf es = new EnhancedBlockStream(new Block(xorBuf), new Block(data, pos, length)); hash = Compute(es, xorBuf.Length + length); // XOR the key with oPad and put the result in xorBuf for (int i = 0; i < 64; i++) { xorBuf[i] = (byte)(key[i] ^ oPad); } // The result is the hash of the combination of hash appended to xorBuf es = new EnhancedBlockStream(new Block(xorBuf), new Block(hash)); return(Compute(es, xorBuf.Length + hash.Length)); }
public void EnhancedBlockStream_ReadWriteBytesNoLen() { var es = new EnhancedBlockStream(); es.WriteBytesNoLen(new byte[] { 0, 1, 2, 3 }); es.Seek(0, SeekOrigin.Begin); CollectionAssert.AreEqual(new byte[] { 0, 1, 2, 3 }, es.ReadBytes(4)); }
public void EnhancedBlockStream_Float() { var es = new EnhancedBlockStream(); float f; es.WriteFloat((float)123.456); es.Seek(0, SeekOrigin.Begin); f = es.ReadFloat(); Assert.AreEqual((float)123.456, f); }
public void EnhancedBlockStream_ReadStringCb() { var es = new EnhancedBlockStream(); int cb; es.WriteStringNoLen("Hello World!"); cb = (int)es.Position; es.Seek(0, SeekOrigin.Begin); Assert.AreEqual("Hello World!", es.ReadString(cb)); }
/// <summary> /// Constructs a database package builder that will create a /// package at the specified file system path. /// </summary> /// <param name="setupPath">Path of the setup information.</param> /// <remarks> /// <para> /// The setupInfo file must define these values: /// </para> /// <code language="cs"> /// SetupTitle = [database setup wizard title] /// ProductName = [product name] /// ProductID = [GUID] /// ProductVersion = [version] /// DatabaseType = [purpose] /// SchemaVersion = [version] /// </code> /// </remarks> public DBPackageBuilder(string setupPath) { const string MissingValue = "Missing setup value [{0}]."; bs = new EnhancedBlockStream(); package = new Package(); package.Create(bs); package.AddFolder("/Schema"); package.AddFolder("/Procs"); package.AddFolder("/Funcs"); package.AddFolder("/Upgrade"); package.AddFile("/Setup.ini", setupPath); // Validate setup.ini Config config; StreamReader reader; reader = new StreamReader(setupPath, Helper.AnsiEncoding); try { config = new Config(null, reader); if (config.Get("SetupTitle") == null) { throw new ArgumentException(string.Format(MissingValue, "SetupTitle")); } if (config.Get("ProductName") == null) { throw new ArgumentException(string.Format(MissingValue, "ProductName")); } if (config.Get("ProductID") == null) { throw new ArgumentException(string.Format(MissingValue, "ProductID")); } if (config.Get("ProductVersion") == null) { throw new ArgumentException(string.Format(MissingValue, "ProductVersion")); } if (config.Get("DatabaseType") == null) { throw new ArgumentException(string.Format(MissingValue, "DatabaseType")); } if (config.Get("SchemaVersion") == null) { throw new ArgumentException(string.Format(MissingValue, "SchemaVersion")); } } finally { reader.Close(); } }
public void EnhancedBlockStream_Bool() { var es = new EnhancedBlockStream(); es.WriteBool(true); es.WriteBool(false); es.Seek(0, SeekOrigin.Begin); Assert.IsTrue(es.ReadBool()); Assert.IsFalse(es.ReadBool()); }
public void EnhancedBlockStream_Byte() { var es = new EnhancedBlockStream(); es.WriteByte(77); es.WriteByte(99); es.Seek(0, SeekOrigin.Begin); Assert.AreEqual(77, es.ReadByte()); Assert.AreEqual(99, es.ReadByte()); }
public void EnhancedBlockStream_String32() { var es = new EnhancedBlockStream(); es.WriteString32(null); es.WriteString32("Hello World!"); es.WriteString32(new String('a', 45000)); es.Seek(0, SeekOrigin.Begin); Assert.IsNull(es.ReadString32()); Assert.AreEqual("Hello World!", es.ReadString32()); Assert.AreEqual(new String('a', 45000), es.ReadString32()); }
public void Package_HashVerify() { Package package; EnhancedBlockStream bs = new EnhancedBlockStream(); EnhancedMemoryStream es = new EnhancedMemoryStream(); PackageEntry entry; byte[] buf; byte v; buf = new byte[37000]; for (int i = 0; i < buf.Length; i++) { buf[i] = (byte)i; } //------------------------- package = new Package(); package.Create(es); bs.WriteBytes32(buf); bs.Position = 0; entry = package.AddFile("/Foo/Bar/Test1.dat", bs, (int)bs.Length); Assert.IsTrue(bs.Eof); Assert.IsTrue(entry.IsFile); Assert.IsTrue(package["/Foo"].IsFolder); Assert.IsTrue(package["/Foo/Bar"].IsFolder); Assert.IsTrue(package["/Foo/Bar/Test1.dat"].IsFile); package.Close(true); es.Position = es.Length / 2; // Corrupt a byte in the middle of the stream // to verify that the MD5 hash comparision // catches it. v = (byte)es.ReadByte(); es.Seek(-1, SeekOrigin.Current); es.WriteByte((byte)~v); es.Position = 0; try { package = new Package(es); Assert.Fail(); } catch (PackageException) { } }
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()); }
public void EnhancedBlockStream_Int16() { var es = new EnhancedBlockStream(); es.WriteInt16(0); es.WriteInt16(55); es.WriteInt16(0x1234); es.Seek(0, SeekOrigin.Begin); Assert.AreEqual(0, es.ReadInt16()); Assert.AreEqual(55, es.ReadInt16()); Assert.AreEqual(0x1234, es.ReadInt16()); }
public void EnhancedBlockStream_Int32() { var es = new EnhancedBlockStream(); es.WriteInt32(0); es.WriteInt32(65121); es.WriteInt32(0x12345678); es.Seek(0, SeekOrigin.Begin); Assert.AreEqual(0, es.ReadInt32()); Assert.AreEqual(65121, es.ReadInt32()); Assert.AreEqual(0x12345678, es.ReadInt32()); }
public void Package_AddStream() { Package package; EnhancedBlockStream bs = new EnhancedBlockStream(); EnhancedMemoryStream es = new EnhancedMemoryStream(); PackageEntry entry; byte[] buf; buf = new byte[37000]; for (int i = 0; i < buf.Length; i++) { buf[i] = (byte)i; } //------------------------- package = new Package(); package.Create(es); bs.WriteBytes32(buf); bs.Position = 0; entry = package.AddFile("/Foo/Bar/Test1.dat", bs, (int)bs.Length); Assert.IsTrue(bs.Eof); Assert.IsTrue(entry.IsFile); Assert.IsTrue(package["/Foo"].IsFolder); Assert.IsTrue(package["/Foo/Bar"].IsFolder); Assert.IsTrue(package["/Foo/Bar/Test1.dat"].IsFile); package.Close(true); //------------------------- es.Position = 0; package = new Package(es); Assert.IsTrue(entry.IsFile); Assert.IsTrue(package["/Foo"].IsFolder); Assert.IsTrue(package["/Foo/Bar"].IsFolder); Assert.IsTrue(package["/Foo/Bar/Test1.dat"].IsFile); bs.SetLength(0); package["/Foo/Bar/Test1.dat"].GetContents(bs); bs.Position = 0; CollectionAssert.AreEqual(buf, bs.ReadBytes32()); package.Close(); }
/// <summary> /// Generates a clone of this message instance, generating a new /// <see cref="_MsgID" /> property if the original ID is /// not empty. /// </summary> /// <returns>Returns a clone of the message.</returns> /// <remarks> /// <para> /// This base method works by serializing and then deseralizing a new copy of /// the message to a buffer and then generating a new <see cref="_MsgID" /> GUID. This /// implementation will be relatively costly in terms of processor and /// memory resources. /// </para> /// <para> /// Derived messages can choose to override this and implement a shallow /// clone instead, using the <see cref="CopyBaseFields" /> method. Note that /// the <see cref="CopyBaseFields" /> method ensures that a new <see cref="_MsgID" /> /// property is regenerated if the original ID field is not empty. /// </para> /// </remarks> public virtual Msg Clone() { var es = new EnhancedBlockStream(1024, 1024); Msg clone; Msg.Save(es, this); es.Position = 0; clone = Msg.Load(es); if (this.msgID != Guid.Empty) { clone.msgID = Helper.NewGuid(); } return(clone); }
public void EnhancedBlockStream_Int64() { var es = new EnhancedBlockStream(); es.WriteInt64(0); es.WriteInt64(65121); es.WriteInt64(0x12345678); es.WriteInt64((((long)0x12345678) << 32) | (long)0xaabbccddee); es.Seek(0, SeekOrigin.Begin); Assert.AreEqual(0, es.ReadInt64()); Assert.AreEqual(65121, es.ReadInt64()); Assert.AreEqual(0x12345678, es.ReadInt64()); Assert.AreEqual((((long)0x12345678) << 32) | (long)0xaabbccddee, es.ReadInt64()); }
public void EnhancedBlockStream_VerifyBufLength() { var es = new EnhancedBlockStream(); es.WriteInt16(5000); es.Seek(0, SeekOrigin.Begin); try { es.ReadBytes16(); Assert.Fail(); } catch { } es.Seek(0, SeekOrigin.Begin); try { es.ReadString16(); Assert.Fail(); } catch { } es.Seek(0, SeekOrigin.Begin); es.WriteInt32(500000); try { es.ReadBytes32(); Assert.Fail(); } catch { } es.Seek(0, SeekOrigin.Begin); try { es.ReadString32(); Assert.Fail(); } catch { } }
/// <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(); } }