Ejemplo n.º 1
0
        private static byte[] CtapCanonicalEncode(CBORObject a, int depth)
        {
            CBORObject cbor       = a.Untag();
            CBORType   valueAType = cbor.Type;

            try {
                if (valueAType == CBORType.Array)
                {
                    using (var ms = new MemoryStream()) {
                        CBORObject.WriteValue(ms, 4, cbor.Count);
                        for (var i = 0; i < cbor.Count; ++i)
                        {
                            if (depth >= 3 && IsArrayOrMap(cbor[i]))
                            {
                                throw new CBORException("Nesting level too deep");
                            }
                            byte[] bytes = CtapCanonicalEncode(cbor[i], depth + 1);
                            ms.Write(bytes, 0, bytes.Length);
                        }
                        return(ms.ToArray());
                    }
                }
                else if (valueAType == CBORType.Map)
                {
                    KeyValuePair <byte[], byte[]>         kv1;
                    List <KeyValuePair <byte[], byte[]> > sortedKeys;
                    sortedKeys = new List <KeyValuePair <byte[], byte[]> >();
                    foreach (CBORObject key in cbor.Keys)
                    {
                        if (depth >= 3 && (IsArrayOrMap(key) ||
                                           IsArrayOrMap(cbor[key])))
                        {
                            throw new CBORException("Nesting level too deep");
                        }
                        CheckDepth(key, depth + 1);
                        CheckDepth(cbor[key], depth + 1);
                        // Check if key and value can be canonically encoded
                        // (will throw an exception if they cannot)
                        kv1 = new KeyValuePair <byte[], byte[]>(
                            CtapCanonicalEncode(key, depth + 1),
                            CtapCanonicalEncode(cbor[key], depth + 1));
                        sortedKeys.Add(kv1);
                    }
                    sortedKeys.Sort(ByteComparer);
                    using (var ms = new MemoryStream()) {
                        CBORObject.WriteValue(ms, 5, cbor.Count);
                        byte[] lastKey = null;
                        for (var i = 0; i < sortedKeys.Count; ++i)
                        {
                            kv1 = sortedKeys[i];
                            byte[] bytes = kv1.Key;
                            if (lastKey != null && ByteArraysEqual(bytes, lastKey))
                            {
                                throw new CBORException("duplicate canonical CBOR key");
                            }
                            lastKey = bytes;
                            ms.Write(bytes, 0, bytes.Length);
                            bytes = kv1.Value;
                            ms.Write(bytes, 0, bytes.Length);
                        }
                        return(ms.ToArray());
                    }
                }
            } catch (IOException ex) {
                throw new InvalidOperationException(ex.ToString(), ex);
            }
            if (valueAType == CBORType.SimpleValue ||
                valueAType == CBORType.Boolean || valueAType == CBORType.ByteString ||
                valueAType == CBORType.TextString)
            {
                return(cbor.EncodeToBytes(CBOREncodeOptions.Default));
            }
            else if (valueAType == CBORType.FloatingPoint)
            {
                long bits = cbor.AsDoubleBits();
                return(new byte[] {
                    (byte)0xfb,
                    (byte)((bits >> 56) & 0xffL),
                    (byte)((bits >> 48) & 0xffL),
                    (byte)((bits >> 40) & 0xffL),
                    (byte)((bits >> 32) & 0xffL),
                    (byte)((bits >> 24) & 0xffL),
                    (byte)((bits >> 16) & 0xffL),
                    (byte)((bits >> 8) & 0xffL),
                    (byte)(bits & 0xffL),
                });
            }
            else if (valueAType == CBORType.Integer)
            {
                return(cbor.EncodeToBytes(CBOREncodeOptions.Default));
            }
            else
            {
                throw new ArgumentException("Invalid CBOR type.");
            }
        }