예제 #1
0
        private void TestEncoding(long input)
        {
            int length = Pascal.EncodedLength(input);

            sbyte[] trits = new sbyte[length];

            Pascal.Encode(input, trits);

            var result = Pascal.Decode(trits);

            Assert.AreEqual(input, result.Item1);
            Assert.AreEqual(trits.Length, result.Item2);
        }
예제 #2
0
        public void TestValueDecoding()
        {
            var expected      = new Tuple <int, int>(0, 4);
            var valueToDecode = new[] { 1, 0, 0, -1 };
            var result        = Pascal.Decode(valueToDecode);

            Assert.AreEqual(expected.Item1, result.Item1);
            Assert.AreEqual(expected.Item2, result.Item2);

            expected      = new Tuple <int, int>(1000, 12);
            valueToDecode = new[] { -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, 0 };
            result        = Pascal.Decode(valueToDecode);

            Assert.AreEqual(expected.Item1, result.Item1);
            Assert.AreEqual(expected.Item2, result.Item2);

            valueToDecode = new[] { -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1 };
            result        = Pascal.Decode(valueToDecode);

            Assert.AreEqual(expected.Item1, result.Item1);
            Assert.AreEqual(expected.Item2, result.Item2);
        }
예제 #3
0
        /// <inheritdoc />
        public UnmaskedAuthenticatedMessage Unmask(Bundle payload, TryteString root, TryteString channelKey)
        {
            var payloadTrits = payload.Transactions.Select(t => t.Fragment).ToList().Merge().ToTrits();

            // Get data indices
            var indexData     = Pascal.Decode(payloadTrits);
            var index         = indexData.Item1;
            var messageData   = Pascal.Decode(payloadTrits.Skip(indexData.Item2).ToArray());
            var messageLength = messageData.Item1;
            var nextRootStart = indexData.Item2 + messageData.Item2;
            var messageStart  = nextRootStart + Constants.TritHashLength;
            var messageEnd    = messageStart + messageLength;

            // Absorb key, root, index and message trits
            this.Curl.Reset();
            this.Curl.Absorb(channelKey.ToTrits());
            this.Curl.Absorb(root.ToTrits());
            this.Curl.Absorb(payloadTrits.Take(nextRootStart).ToArray());

            // decrypt metadata and create hmac
            var nextRoot = this.Mask.Unmask(payloadTrits.Skip(nextRootStart).Take(Constants.TritHashLength).ToArray(), this.Curl);
            var message  = this.Mask.Unmask(payloadTrits.Skip(messageStart).Take(messageLength).ToArray(), this.Curl);
            var nonce    = this.Mask.Unmask(payloadTrits.Skip(messageEnd).Take(Constants.TritHashLength / 3).ToArray(), this.Curl);
            var hmac     = this.Curl.Rate(Constants.TritHashLength);

            // verify security level with hmac
            var securityLevel = this.SigningHelper.ChecksumSecurity(hmac);

            if (securityLevel == 0)
            {
                throw new ArgumentException("Given payload is invalid. (Security level can not be verified)");
            }

            // decrypt remaining payload
            var decryptedMetadata = this.Mask.Unmask(payloadTrits.Skip(messageEnd + nonce.Length).ToArray(), this.Curl);

            this.Curl.Reset();

            // get signature, derive digest and absorb it
            var signature = decryptedMetadata.Take(securityLevel * PrivateKey.FragmentLength).ToArray();

            this.Curl.Absorb(this.SigningHelper.DigestFromSignature(hmac, signature));

            // decode sibling information and recalculate root to verify payload
            var siblingsCountData = Pascal.Decode(decryptedMetadata.Skip(securityLevel * PrivateKey.FragmentLength).ToArray());
            var siblingsCount     = siblingsCountData.Item1;
            var recalculatedRoot  = siblingsCount != 0
                           ? this.RecalculateRootWithSiblings(decryptedMetadata, securityLevel, siblingsCountData.Item2, siblingsCount, index)
                           : new Hash(Converter.TritsToTrytes(this.Curl.Rate(Constants.TritHashLength)));

            if (recalculatedRoot.Value != root.Value)
            {
                throw new ArgumentException("Given payload is invalid. (Given root does not match payload root)");
            }

            return(new UnmaskedAuthenticatedMessage
            {
                NextRoot = new Hash(Converter.TritsToTrytes(nextRoot)),
                Message = new TryteString(Converter.TritsToTrytes(message)),
                Root = new Hash(root.Value)
            });
        }
예제 #4
0
        /// <inheritdoc />
        public UnmaskedAuthenticatedMessage Unmask(Bundle payload, TryteString root, TryteString channelKey)
        {
            var payloadTrits = payload.Transactions.Select(t => t.Fragment).ToList().Merge().ToTrits();

            var indexData = Pascal.Decode(payloadTrits);
            var index     = indexData.Item1;

            var messageData   = Pascal.Decode(payloadTrits.Skip(indexData.Item2).ToArray());
            var messageLength = messageData.Item1;
            var nextRootStart = indexData.Item2 + messageData.Item2;
            var messageStart  = nextRootStart + Constants.TritHashLength;
            var messageEnd    = messageStart + messageLength;

            this.Curl.Reset();
            this.Curl.Absorb(channelKey.ToTrits());
            this.Curl.Absorb(root.ToTrits());
            this.Curl.Absorb(payloadTrits.Take(nextRootStart).ToArray());

            var nextRoot = this.Mask.Unmask(payloadTrits.Skip(nextRootStart).Take(Constants.TritHashLength).ToArray(), this.Curl);
            var message  = this.Mask.Unmask(payloadTrits.Skip(messageStart).Take(messageLength).ToArray(), this.Curl);
            var nonce    = this.Mask.Unmask(payloadTrits.Skip(messageEnd).Take(Constants.TritHashLength / 3).ToArray(), this.Curl);
            var hmac     = this.Curl.Rate(Constants.TritHashLength);

            var securityLevel = this.SigningHelper.ChecksumSecurity(hmac);

            if (securityLevel == 0)
            {
                throw new ArgumentException("Given payload is invalid. (Security level can not be verified)");
            }

            var decryptedMetadata = this.Mask.Unmask(payloadTrits.Skip(messageEnd + nonce.Length).ToArray(), this.Curl);
            var signature         = decryptedMetadata.Take(securityLevel * PrivateKey.FragmentLength).ToArray();

            var digest = this.SigningHelper.DigestFromSignature(hmac, signature);

            this.Curl.Reset();
            this.Curl.Absorb(digest);

            var siblingsCountData = Pascal.Decode(decryptedMetadata.Skip(securityLevel * PrivateKey.FragmentLength).ToArray());
            var siblingsCount     = siblingsCountData.Item1;

            Hash recalculatedRoot;

            if (siblingsCount != 0)
            {
                var siblings = decryptedMetadata.Skip((securityLevel * PrivateKey.FragmentLength) + siblingsCountData.Item2)
                               .Take(siblingsCount * Constants.TritHashLength).ToArray();

                recalculatedRoot = this.TreeFactory.RecalculateRoot(
                    siblings,
                    this.Curl.Rate(Constants.TritHashLength),
                    index);
            }
            else
            {
                recalculatedRoot = new Hash(Converter.TritsToTrytes(this.Curl.Rate(Constants.TritHashLength)));
            }

            if (recalculatedRoot.Value != root.Value)
            {
                throw new ArgumentException("Given payload is invalid. (Given root does not match payload root)");
            }

            return(new UnmaskedAuthenticatedMessage
            {
                NextRoot = new Hash(Converter.TritsToTrytes(nextRoot)),
                Message = new TryteString(Converter.TritsToTrytes(message)),
                Root = new Hash(root.Value)
            });
        }
예제 #5
0
        /// <summary>
        /// </summary>
        /// <param name="payload"></param>
        /// <param name="sideKey"></param>
        /// <param name="root"></param>
        /// <returns>(message,nextRoot)</returns>
        public Tuple <string, string> DecodeMessage(string payload, string sideKey, string root)
        {
            if (string.IsNullOrEmpty(sideKey))
            {
                sideKey = "999999999999999999999999999999999999999999999999999999999999999999999999999999999";
            }

            var payloadTrits = Converter.ToTrits(payload);
            var sideKeyTrits = Converter.ToTrits(sideKey);
            var rootTrits    = Converter.ToTrits(root);

            ICurl curl = new Curl(SpongeFactory.Mode.CURLP27);

            // parse
            var result   = Pascal.Decode(payloadTrits);
            var index    = (int)result.Item1;
            var indexEnd = result.Item2;

            var tempTrits = new sbyte[payloadTrits.Length - indexEnd];

            Array.Copy(payloadTrits, indexEnd, tempTrits, 0, tempTrits.Length);

            result = Pascal.Decode(tempTrits);
            var messageLength    = (int)result.Item1;
            var messageLengthEnd = result.Item2;

            var nextRootStart = indexEnd + messageLengthEnd;
            var messageStart  = nextRootStart + Constants.HashLength;
            var messageEnd    = messageStart + messageLength;

            curl.Absorb(sideKeyTrits);
            curl.Absorb(rootTrits);

            if (messageLength > payloadTrits.Length)
            {
                throw new ArgumentOutOfRangeException();
            }

            curl.Absorb(payloadTrits, 0, nextRootStart);

            MaskHelper.UnMaskSlice(payloadTrits, nextRootStart, messageStart - nextRootStart, curl);
            MaskHelper.UnMaskSlice(payloadTrits, messageStart, messageEnd - messageStart, curl);

            var pos = messageEnd;

            MaskHelper.UnMaskSlice(payloadTrits, pos, Constants.MessageNonceLength, curl);
            pos += Constants.HashLength / 3;

            var hmac = new sbyte[Constants.HashLength];

            Array.Copy(curl.Rate, hmac, Constants.HashLength);

            var security = HashHelper.CheckSumSecurity(hmac);

            MaskHelper.UnMaskSlice(payloadTrits, pos, payloadTrits.Length - pos, curl);

            if (security == 0)
            {
                // InvalidHash
                curl.Reset();
                throw new ApplicationException();
            }


            var sigEnd = pos + security * Constants.KeyLength;

            HashHelper.DigestBundleSignature(hmac, payloadTrits, pos, sigEnd - pos, curl);

            Array.Copy(curl.Rate, hmac, Constants.HashLength);
            curl.Reset();

            pos       = sigEnd;
            tempTrits = new sbyte[payloadTrits.Length - pos];
            Array.Copy(payloadTrits, pos, tempTrits, 0, tempTrits.Length);
            result = Pascal.Decode(tempTrits);

            curl.Absorb(hmac);
            if (result.Item1 != 0)
            {
                // get address lite
                Array.Copy(curl.Rate, hmac, Constants.HashLength);
                pos += result.Item2;
                var sibEnd = pos + (int)result.Item1;

                var siblings = new sbyte[sibEnd - pos];
                Array.Copy(payloadTrits, pos, siblings, 0, siblings.Length);

                curl.Reset();
                MerkleTree.Root(hmac, siblings, index, curl);
            }

            if (!curl.Rate.SequenceEqual(rootTrits))
            {
                // InvalidSignature
                curl.Reset();
                throw new ApplicationException();
            }

            var message  = Converter.ToTrytes(payloadTrits, messageStart, messageLength);
            var nextRoot = Converter.ToTrytes(payloadTrits, nextRootStart, Constants.HashLength);

            return(new Tuple <string, string>(message, nextRoot));
        }