public void Rfc23279TrySignDataUnderMax() { KeyDescription keyDescription = GetKey(); ECDsa key = (ECDsa)keyDescription.Key; const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; // Make secp521r1 (7/16 chance of being smaller) and mod-8 keys (3/4 chance of being smaller) // have the same 1-in-a-billion chance of failure. int retryCount = keyDescription.FieldSizeInBits % 8 == 1 ? 36 : 15; HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); byte[] signature = new byte[expectedSize]; for (int i = 0; i < retryCount; i++) { if (key.TrySignData(Array.Empty <byte>(), signature, hashAlgorithm, SignatureFormat, out int written)) { return; } Assert.Equal(0, written); } Assert.True(false, $"TrySignData eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); }
public void Rfc23279TrySignHashUnderMax() { KeyDescription keyDescription = GetKey(); ECDsa key = (ECDsa)keyDescription.Key; const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; // Make secp521r1 (7/16 chance of being smaller) and mod-8 keys (3/4 chance of being smaller) // have the same 1-in-a-billion chance of failure. int retryCount = keyDescription.FieldSizeInBits % 8 == 1 ? 36 : 15; byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); byte[] signature = new byte[expectedSize]; for (int i = 0; i < retryCount; i++) { if (key.TrySignHash(hash, signature, SignatureFormat, out int written)) { return; } Assert.Equal(0, written); } Assert.True(false, $"TrySignHash eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); }
public void Rfc23279TrySignDataUnderMax() { KeyDescription keyDescription = GetKey(); ECDsa key = (ECDsa)keyDescription.Key; const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; const int RetryCount = 10; HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); byte[] signature = new byte[expectedSize]; for (int i = 0; i < RetryCount; i++) { if (key.TrySignData(Array.Empty <byte>(), signature, hashAlgorithm, SignatureFormat, out int written)) { return; } Assert.Equal(0, written); } Assert.True(false, $"TrySignData eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); }
protected override byte[] SignHash( KeyDescription key, byte[] hash, DSASignatureFormat signatureFormat) { return(((ECDsa)key.Key).SignHash(hash, signatureFormat)); }
private static void CheckLength(KeyDescription key, byte[] signature, DSASignatureFormat signatureFormat) { int fieldSizeBytes = (key.FieldSizeInBits + 7) / 8; switch (signatureFormat) { case DSASignatureFormat.IeeeP1363FixedFieldConcatenation: Assert.Equal(2 * fieldSizeBytes, signature.Length); break; case DSASignatureFormat.Rfc3279DerSequence: { // SEQUENCE(INTEGER, INTEGER) has a minimum length of 8 (30 06 02 01 00 02 01 00) // The maximum length is a bit more complicated: int elemSize = fieldSizeBytes + 1; int integerMax = 2 + GetDerLengthLength(elemSize) + elemSize; int integersMax = 2 * integerMax; int sequenceMax = 2 + GetDerLengthLength(integersMax) + integersMax; Assert.InRange(signature.Length, 8, sequenceMax); break; } default: throw new InvalidOperationException($"No handler for format {signatureFormat}"); } }
public void VerifyInvalidRfc3279Signature() { KeyDescription key = GetKey(); // This is SEQUENCE(INTEGER(1), INTEGER(0)), except the second integer uses // a length value that exceeds the payload length. // This ensures that we don't throw exceptions after finding out the leading bytes // are valid sequence for the payload length. byte[] invalidSignature = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00 }; Assert.False( VerifyData( key, _typeNameBytes, invalidSignature, HashAlgorithmName.SHA1, DSASignatureFormat.Rfc3279DerSequence), "VerifyData with an illegal DER payload"); Assert.False( VerifyHash( key, _typeNameBytes, invalidSignature, DSASignatureFormat.Rfc3279DerSequence), "VerifyHash with an illegal DER payload"); }
public void Rfc3279SignatureValidatesLength() { KeyDescription key = GetKey(); HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; byte[] signature = SignHash(key, hash, SignatureFormat); byte[] rightPadded = signature.Concat(Enumerable.Repeat((byte)0, 4)).ToArray(); Assert.True( VerifyHash(key, hash, signature, SignatureFormat), "VerifyHash with the unmodified signature"); Assert.False( VerifyHash(key, hash, rightPadded, SignatureFormat), "VerifyHash with the right-padded signature"); signature = SignData(key, hash, hashAlgorithm, SignatureFormat); rightPadded = signature.Concat(Enumerable.Repeat((byte)0, 4)).ToArray(); Assert.True( VerifyData(key, hash, signature, hashAlgorithm, SignatureFormat), "VerifyData with the unmodified signature"); Assert.False( VerifyData(key, hash, rightPadded, hashAlgorithm, SignatureFormat), "VerifyData with the right-padded signature"); }
protected override byte[] SignData( KeyDescription key, byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) { ECDsa dsa = (ECDsa)key.Key; byte[] predictedMax = new byte[dsa.GetMaxSignatureSize(signatureFormat)]; Assert.True( dsa.TrySignData(data, predictedMax, hashAlgorithm, signatureFormat, out int written), "TrySignData with a GetMaxSignatureSize buffer"); if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) { // GetMaxSignatureSize should be exactly accurate for P1363. Assert.Equal(predictedMax.Length, written); } if (written == predictedMax.Length) { return(predictedMax); } return(predictedMax.AsSpan(0, written).ToArray()); }
public void Rfc23279TrySignHashUnderMax() { KeyDescription keyDescription = GetKey(); ECDsa key = (ECDsa)keyDescription.Key; const DSASignatureFormat SignatureFormat = DSASignatureFormat.Rfc3279DerSequence; const int RetryCount = 10; byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; int expectedSize = GetExpectedSize(keyDescription.FieldSizeInBits); int maxSize = key.GetMaxSignatureSize(DSASignatureFormat.Rfc3279DerSequence); Assert.True(expectedSize < maxSize, "expectedSize < maxSize"); byte[] signature = new byte[expectedSize]; for (int i = 0; i < RetryCount; i++) { if (key.TrySignHash(hash, signature, SignatureFormat, out int written)) { return; } Assert.Equal(0, written); } Assert.True(false, $"TrySignHash eventually succeeds with a {expectedSize}/{maxSize}-byte destination"); }
protected override bool VerifyHash( KeyDescription key, byte[] hash, byte[] signature, DSASignatureFormat signatureFormat) { return(((ECDsa)key.Key).VerifyHash(hash, signature, signatureFormat)); }
protected override byte[] SignData( KeyDescription key, byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) { return(((ECDsa)key.Key).SignData(data, hashAlgorithm, signatureFormat)); }
public void SignHashVerifyHash(DSASignatureFormat signatureFormat) { KeyDescription key = GetKey(); byte[] hash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; byte[] signature = SignHash(key, hash, signatureFormat); CheckLength(key, signature, signatureFormat); Assert.True(VerifyHash(key, hash, signature, signatureFormat)); }
public void SignDataVerifyData_SHA1(DSASignatureFormat signatureFormat) { HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; KeyDescription key = GetKey(); byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); CheckLength(key, signature, signatureFormat); Assert.True(VerifyData(key, _typeNameBytes, signature, hashAlgorithm, signatureFormat)); }
public void EmptyHashAlgorithm() { KeyDescription key = GetKey(); byte[] empty = Array.Empty <byte>(); foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) { AssertExtensions.Throws <ArgumentException>( "hashAlgorithm", () => SignData(key, empty, default, format));
protected override bool VerifyHash( KeyDescription key, byte[] hash, byte[] signature, DSASignatureFormat signatureFormat) { ReadOnlySpan <byte> readOnlyHash = hash; ReadOnlySpan <byte> readOnlySignature = signature; return(((ECDsa)key.Key).VerifyHash(readOnlyHash, readOnlySignature, signatureFormat)); }
protected override bool VerifyData( KeyDescription key, byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) { ReadOnlySpan <byte> readOnlyData = data; ReadOnlySpan <byte> readOnlySignature = signature; return(((ECDsa)key.Key).VerifyData(readOnlyData, readOnlySignature, hashAlgorithm, signatureFormat)); }
public void OffsetAndCountOutOfRange() { KeyDescription keyDescription = GetKey(); ECDsa key = (ECDsa)keyDescription.Key; HashAlgorithmName hash = HashAlgorithmName.SHA256; byte[] buffer = new byte[10]; foreach (DSASignatureFormat format in Enum.GetValues(typeof(DSASignatureFormat))) { AssertExtensions.Throws <ArgumentOutOfRangeException>( "offset", () => key.SignData(buffer, -1, buffer.Length, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "offset", () => key.SignData(buffer, buffer.Length + 1, 0, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "offset", () => key.VerifyData(buffer, -1, buffer.Length, buffer, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "offset", () => key.VerifyData(buffer, buffer.Length + 1, 0, buffer, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.SignData(buffer, 1, buffer.Length, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.SignData(buffer, 0, buffer.Length + 1, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.SignData(buffer, buffer.Length, 1, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.VerifyData(buffer, 1, buffer.Length, buffer, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.VerifyData(buffer, 0, buffer.Length + 1, buffer, hash, format)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "count", () => key.VerifyData(buffer, buffer.Length, 1, buffer, hash, format)); } }
public override int StoreToStream(Stream stream, KeyDescription item) { if (item == null) { return(WriteVersionNull(stream)); } var count = stream.WriteIntVariableLength(Version); count += stream.WriteString(item.StringProperty); count += stream.WriteBytes(item.BytesPropery); count += stream.WriteIntVariableLength(item.IntegerProperty); return(count); }
public void SignDataVerifyHash_SHA1(DSASignatureFormat signatureFormat) { HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; KeyDescription key = GetKey(); byte[] signature = SignData(key, _typeNameBytes, hashAlgorithm, signatureFormat); CheckLength(key, signature, signatureFormat); using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm)) { hash.AppendData(_typeNameBytes); Assert.True(VerifyHash(key, hash.GetHashAndReset(), signature, signatureFormat)); } }
protected override byte[] SignData( KeyDescription key, byte[] data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) { int offset = 0; int count = 0; if (data != null) { offset = 2; count = data.Length; byte[] bigger = new byte[count + 7]; Buffer.BlockCopy(data, 0, bigger, offset, count); data = bigger; } return(((ECDsa)key.Key).SignData(data, offset, count, hashAlgorithm, signatureFormat)); }
/// <summary> /// Make sure existing table is valid to be used as a session store. /// </summary> private void ValidateTable() { if (this._table.HashKeys.Count != 1) { throw new AmazonDynamoDBException(string.Format("Table {0} cannot be used to store session data because it does not define a single hash key", this._tableName)); } string hashKey = this._table.HashKeys[0]; KeyDescription hashKeyDescription = this._table.Keys[hashKey]; if (hashKeyDescription.Type != DynamoDBEntryType.String) { throw new AmazonDynamoDBException(string.Format("Table {0} cannot be used to store session data because hash key is not a string.", this._tableName)); } if (this._table.RangeKeys.Count > 0) { throw new AmazonDynamoDBException(string.Format("Table {0} cannot be used to store session data because it contains a range key in its schema.", this._tableName)); } ATTRIBUTE_SESSION_ID = hashKey; }
public void SignatureFormatsAreNotCompatible(DSASignatureFormat signFormat, DSASignatureFormat verifyFormat) { if (!SupportsSha2) { return; } HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; const int RetryCount = 10; KeyDescription key = GetKey(); byte[] hash; using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm)) { hasher.AppendData(_typeNameBytes); hash = hasher.GetHashAndReset(); } for (int i = 0; i < RetryCount; i++) { byte[] signature = SignData( key, _typeNameBytes, hashAlgorithm, signFormat); if (!VerifyData(key, _typeNameBytes, signature, hashAlgorithm, verifyFormat)) { Assert.False( VerifyHash(key, hash, signature, verifyFormat), $"VerifyHash({verifyFormat}) verifies after VerifyData({verifyFormat}) fails"); return; } } Assert.False(true, $"{RetryCount} {signFormat} signatures verified as {verifyFormat} signatures"); }
static KeyDescription[] FindKeys() { var foundKeys = new List <KeyDescription>(); var type = typeof(KeyEventType); var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); foreach (var field in fields) { var pref = new KeyDescription(); var attribute = field.GetCustomAttributes(typeof(KeyDescriptionAttribute), false).FirstOrDefault() as KeyDescriptionAttribute; if (attribute == null) { continue; } pref.Value = (KeyEventType)field.GetValue(null); pref.KeyEvent = attribute.KeyEvent; foundKeys.Add(pref); } return(foundKeys.ToArray()); }
public void BadSignatureFormat() { KeyDescription key = GetKey(); const DSASignatureFormat SignatureFormat = (DSASignatureFormat)3; byte[] empty = Array.Empty <byte>(); AssertExtensions.Throws <ArgumentOutOfRangeException>( "signatureFormat", () => SignData(key, empty, HashAlgorithmName.SHA1, SignatureFormat)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "signatureFormat", () => VerifyData(key, empty, empty, HashAlgorithmName.SHA1, SignatureFormat)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "signatureFormat", () => SignHash(key, empty, SignatureFormat)); AssertExtensions.Throws <ArgumentOutOfRangeException>( "signatureFormat", () => VerifyHash(key, empty, empty, SignatureFormat)); }
private void LoadTableInfo() { ClearTableData(); bool staleCacheData; TableDescription table = TableInfoCache.GetValue(TableName, this.DescribeTable, out staleCacheData); this.ContainsCachedData = staleCacheData; if (this.ContainsCachedData) LoggerInstance.InfoFormat("Description for table [{0}] loaded from SDK Cache", TableName); foreach (var key in table.KeySchema) { string keyName = key.AttributeName; AttributeDefinition attributeDefinition = table.AttributeDefinitions .FirstOrDefault(a => string.Equals(a.AttributeName, keyName, StringComparison.Ordinal)); if (attributeDefinition == null) throw new InvalidOperationException("No attribute definition found for key " + key.AttributeName); KeyDescription keyDescription = new KeyDescription { IsHash = string.Equals(key.KeyType, "HASH", StringComparison.OrdinalIgnoreCase), Type = GetType(attributeDefinition.AttributeType) }; if (keyDescription.IsHash) HashKeys.Add(keyName); else RangeKeys.Add(keyName); Keys[keyName] = keyDescription; } if (table.LocalSecondaryIndexes != null) { foreach (var index in table.LocalSecondaryIndexes) { LocalSecondaryIndexes[index.IndexName] = index; LocalSecondaryIndexNames.Add(index.IndexName); } } if (table.GlobalSecondaryIndexes != null) { foreach (var index in table.GlobalSecondaryIndexes) { GlobalSecondaryIndexes[index.IndexName] = index; GlobalSecondaryIndexNames.Add(index.IndexName); } } foreach (var attribute in table.AttributeDefinitions) { Attributes.Add(attribute); } KeyNames = Keys.Keys.ToArray(); }
protected abstract bool VerifyData( KeyDescription key, byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat);
protected abstract bool VerifyHash( KeyDescription key, byte[] hash, byte[] signature, DSASignatureFormat signatureFormat);
protected abstract byte[] SignHash( KeyDescription key, byte[] hash, DSASignatureFormat signatureFormat);
private void GetTableInfo() { DescribeTableRequest req = new DescribeTableRequest { TableName = TableName }; req.BeforeRequestEvent += new RequestEventHandler(this.UserAgentRequestEventHandlerSync); DescribeTableResult info = this.DDBClient.DescribeTable(req); if (info.Table == null) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Table name {0} does not exist", TableName)); } Keys.Clear(); HashKeys.Clear(); RangeKeys.Clear(); TableDescription table = info.Table; foreach (var key in table.KeySchema) { string keyName = key.AttributeName; AttributeDefinition attributeDefinition = table.AttributeDefinitions .FirstOrDefault(a => string.Equals(a.AttributeName, keyName, StringComparison.Ordinal)); if (attributeDefinition == null) throw new InvalidOperationException("No attribute definition found for key " + key.AttributeName); KeyDescription keyDescription = new KeyDescription { IsHash = string.Equals(key.KeyType, "HASH", StringComparison.OrdinalIgnoreCase), Type = GetType(attributeDefinition.AttributeType) }; if (keyDescription.IsHash) HashKeys.Add(keyName); else RangeKeys.Add(keyName); Keys[keyName] = keyDescription; } LocalSecondaryIndexes.Clear(); LocalSecondaryIndexNames.Clear(); if (table.LocalSecondaryIndexes != null) { foreach (var index in table.LocalSecondaryIndexes) { LocalSecondaryIndexes[index.IndexName] = index; LocalSecondaryIndexNames.Add(index.IndexName); } } GlobalSecondaryIndexes.Clear(); GlobalSecondaryIndexNames.Clear(); if (table.GlobalSecondaryIndexes != null) { foreach (var index in table.GlobalSecondaryIndexes) { GlobalSecondaryIndexes[index.IndexName] = index; GlobalSecondaryIndexNames.Add(index.IndexName); } } Attributes.Clear(); foreach (var attribute in table.AttributeDefinitions) { Attributes.Add(attribute); } keyNames = Keys.Keys.ToArray(); }
/// <summary> /// Deserialize graph from graphml file /// </summary> /// <typeparam name="T"></typeparam> /// <param name="xml"></param> /// <param name="includeCost">if true the returned list will contain two Ops: [root, cost]</param> /// <returns></returns> public static List <Op <T> > FromXml <T>(string xml, bool includeCost) where T : struct, IEquatable <T>, IFormattable { var root = ""; var cost = ""; var keys = new Dictionary <string, KeyDescription>(); var nodes = new Dictionary <string, Node>(); var edges = new List <Edge>(); using (var sw = new StringReader(xml)) { using (var reader = XmlReader.Create(sw)) { reader.MoveToContent(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.Name) { case "key": { var id = reader.GetAttribute("id"); var name = reader.GetAttribute("attr.name"); var firstDot = name.IndexOf('.'); if (firstDot != -1) { name = name.Substring(name.IndexOf('.') + 1, name.Length - name.IndexOf('.') - 1); } keys[id] = new KeyDescription { Id = id, Name = name }; } break; case "node": { var id = reader.GetAttribute("id"); var node = new Node { Id = id }; nodes[id] = node; // Move to data section do { reader.Read(); } while (reader.Name != "data"); // Parse data do { var key = reader.GetAttribute("key"); var keyDesc = keys[key]; node.Data[keyDesc.Name] = reader.ReadElementContentAsString(); reader.Read(); } while (reader.Name == "data"); } break; case "edge": { var source = reader.GetAttribute("source"); var target = reader.GetAttribute("target"); edges.Add(new Edge { Source = source, Target = target }); } break; case "data": { var key = reader.GetAttribute("key"); var keyDesc = keys[key]; if (keyDesc.Name == "root") { root = reader.ReadElementContentAsString(); } else if (keyDesc.Name == "cost") { cost = reader.ReadElementContentAsString(); } } break; } } } } } // Create Ops var ops = new Dictionary <string, Op <T> >(); foreach (var node in nodes) { var type = Type.GetType((string)node.Value.Data["type"]); var op = (Op <T>)Activator.CreateInstance(type, node.Value.Data); ops[node.Key] = op; } // Link Ops foreach (var edge in edges) { var source = ops[edge.Source]; var target = ops[edge.Target]; target.AddParent(source); } var result = new List <Op <T> > { ops[root] }; if (includeCost) { if (cost != null) { result.Add(ops[cost]); } } return(result); }
/// <summary> /// Serialize graph to graphml /// </summary> /// <typeparam name="T"></typeparam> /// <param name="op">Root op</param> /// <param name="costOp">Optional cost Op</param> /// <returns></returns> public static string ToXml <T>(this Op <T> op, Op <T> costOp = null) where T : struct, IEquatable <T>, IFormattable { var id = 0; var set = new Dictionary <Op <T>, string>(); var keys = new Dictionary <string, KeyDescription> { { "d0", new KeyDescription { Id = "d0", Name = "type" } }, { "d1", new KeyDescription { Id = "d1", Name = "root", @for = "graph" } }, { "d2", new KeyDescription { Id = "d2", Name = "cost", @for = "graph" } } }; // Retrieve all ops and assign an Id var visitor = new OpVisitor <T>(o => { if (!set.ContainsKey(o)) { set.Add(o, "n" + id++); } }); op.Accept(visitor); costOp?.Accept(visitor); using (var sw = new StringWriter()) { using (var writer = XmlWriter.Create(sw, new XmlWriterSettings { NewLineOnAttributes = true, Indent = true })) { var ns = "http://graphml.graphdrawing.org/xmlns"; writer.WriteStartDocument(); writer.WriteStartElement("graphml", ns); writer.WriteAttributeString("xmlns", ns); // Get all keys var keyId = 3; foreach (var pair in set) { var data = pair.Key.GetData(); if (data.Any()) { foreach (var o in data) { var name = pair.Key.GetType().Name + "." + o.Key; if (!keys.ContainsKey(name)) { keys[name] = new KeyDescription { Id = "d" + keyId++, Name = name }; } } } } // Generate key xml foreach (var keyDescription in keys.Values) { writer.WriteStartElement("key"); writer.WriteAttributeString("id", keyDescription.Id); writer.WriteAttributeString("for", "node"); writer.WriteAttributeString("attr.name", keyDescription.Name); writer.WriteAttributeString("attr.type", "string"); writer.WriteEndElement(); } writer.WriteStartElement("graph"); writer.WriteAttributeString("id", "G"); writer.WriteAttributeString("edgedefault", "directed"); // Root writer.WriteStartElement("data"); writer.WriteAttributeString("key", "d1"); writer.WriteString(set[op]); writer.WriteEndElement(); // Cost if provided if (costOp != null) { writer.WriteStartElement("data"); writer.WriteAttributeString("key", "d2"); writer.WriteString(set[costOp]); writer.WriteEndElement(); } foreach (var pair in set) { writer.WriteStartElement("node"); writer.WriteAttributeString("id", pair.Value); writer.WriteStartElement("data"); writer.WriteAttributeString("key", "d0"); writer.WriteString(pair.Key.GetType().FullName); writer.WriteEndElement(); var data = pair.Key.GetData(); if (data.Any()) { foreach (var o in data) { var name = pair.Key.GetType().Name + "." + o.Key; var keyDesc = keys[name]; writer.WriteStartElement("data"); writer.WriteAttributeString("key", keyDesc.Id); writer.WriteString(o.Value.ToString()); writer.WriteEndElement(); } } writer.WriteEndElement(); } foreach (var pair in set) { foreach (var valueParent in pair.Key.Parents) { writer.WriteStartElement("edge"); writer.WriteAttributeString("source", set[valueParent]); writer.WriteAttributeString("target", set[pair.Key]); writer.WriteEndElement(); } } writer.WriteEndElement(); writer.WriteEndElement(); } return(sw.ToString()); } }