Beispiel #1
0
 public static byte[] ExportKey(IntPtr key, IntPtr pubKey, KeyBlob blobType)
 {
     uint flags = 0;
     //byte[] data = new byte[0]; //did not work for PROV_DSS_DH
     byte[] data = null;
     uint dataLen = 0;
     //length
     bool retVal = Crypto.CryptExportKey(key, pubKey, (uint) blobType, flags, data, ref dataLen);
     //ErrCode ec = Error.HandleRetVal(retVal, ErrCode.MORE_DATA);
     //if(ec == ErrCode.MORE_DATA)
     ErrCode ec = Error.HandleRetVal(retVal);
     if(dataLen != 0)
     {
         //data
         data = new byte[dataLen];
         retVal = Crypto.CryptExportKey(key, pubKey, (uint) blobType, flags, data, ref dataLen);
         ec = Error.HandleRetVal(retVal);
     }
     return data;
 }
Beispiel #2
0
        public void TryGenerateCert()
        {
            int      rc;
            KeyBlob  keyBlob  = new KeyBlob();
            Template template = new Template();

            byte[] output = new byte[Device.MAX_TPM_BUFFER];

            string subject = "/C=US/ST=Oregon/L=Portland/SN=Development" +
                             "/O=wolfSSL/OU=RSA/CN=www.wolfssl.com" +
                             "/[email protected]";
            string keyUsage = "serverAuth,clientAuth,codeSigning";

            Console.WriteLine("Testing generate Certificate");

            rc = template.GetKeyTemplate_RSA((ulong)(
                                                 TPM2_Object.sensitiveDataOrigin |
                                                 TPM2_Object.userWithAuth |
                                                 TPM2_Object.decrypt |
                                                 TPM2_Object.sign |
                                                 TPM2_Object.noDA));
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            rc = device.CreateKey(keyBlob, parent_key, template,
                                  "ThisIsMyStorageKeyAuth");
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            rc = device.LoadKey(keyBlob, parent_key);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            /* Generate a self signed certificate */
            rc = device.GenerateCSR(keyBlob, subject, keyUsage,
                                    X509_Format.PEM, output, 0, 1);
            Assert.That(rc, Is.GreaterThan(0));

            Console.WriteLine("Cert PEM {0} bytes", rc.ToString());

            rc = device.UnloadHandle(keyBlob);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);
        }
Beispiel #3
0
        public static byte [] ExportKey(IntPtr key, IntPtr pubKey, KeyBlob blobType)
        {
            uint flags = 0;

            //byte[] data = new byte[0]; //did not work for PROV_DSS_DH
            byte[] data    = null;
            uint   dataLen = 0;
            //length
            bool retVal = NativeMethods.CryptExportKey(key, pubKey, (uint)blobType, flags, data, ref dataLen);
            //ErrCode ec = Error.HandleRetVal(retVal, ErrCode.MORE_DATA);
            //if(ec == ErrCode.MORE_DATA)
            ErrCode ec = Error.HandleRetVal(retVal);

            if (dataLen != 0)
            {
                //data
                data   = new byte[dataLen];
                retVal = NativeMethods.CryptExportKey(key, pubKey, (uint)blobType, flags, data, ref dataLen);
                ec     = Error.HandleRetVal(retVal);
            }
            return(data);
        }
Beispiel #4
0
        public DiffHell(byte [] rawKey)
        {
            this.rawKey = rawKey; //400 //144

            pks = new PUBLICKEYSTRUC();
            pks.bType = rawKey[0]; //7 //6
            pks.bVersion = rawKey[1]; //2
            pks.reserved = BitConverter.ToUInt16(rawKey, 2); //0
            pks.aiKeyAlg = BitConverter.ToUInt32(rawKey, 4); //43522

            kb = (KeyBlob) pks.bType; //private //public
            c = (Calg) pks.aiKeyAlg; //DH_EPHEM or DH_SF

            if(kb != KeyBlob.PUBLICKEYBLOB && kb != KeyBlob.PRIVATEKEYBLOB)
                throw new Exception("unsupported blob type");

            dhpk = new DHPUBKEY();
            //PRIV 0x32484400. This hex value is the ASCII encoding of "DH2."
            //PUB 0x31484400. This hex value is the ASCII encoding of "DH1."
            dhpk.magic = BitConverter.ToUInt32(rawKey, 8); //843596800 //826819584
            //Number of bits in the prime modulus, P.
            dhpk.bitlen = BitConverter.ToUInt32(rawKey, 12); //1024
            uint byteLen = dhpk.bitlen / 8; //128

            this.SetSizeAndPosition(dhpk.bitlen);

            bool revBytes = true;
            if(kb == KeyBlob.PRIVATEKEYBLOB)
            {
                P = Format.GetBytes(this.rawKey, ypPos, ypLen, revBytes);
                G = Format.GetBytes(this.rawKey, gPos, gLen, revBytes);
                X = Format.GetBytes(this.rawKey, xPos, xLen, revBytes);
            }
            if(kb == KeyBlob.PUBLICKEYBLOB)
            {
                Y = Format.GetBytes(this.rawKey, ypPos, ypLen, revBytes);
            }
        }
Beispiel #5
0
        public void TryImportRSAPrivateKey()
        {
            int rc;

            KeyBlob blob;
            int     exp = 0x10001;

            Console.WriteLine("Testing import RSA Private key");

            PrintByteArray(pub_buffer);
            PrintByteArray(priv_buffer);

            blob = new KeyBlob();

            rc = device.ImportRsaPrivateKey(parent_key, blob,
                                            pub_buffer,
                                            exp, priv_buffer,
                                            (uint)TPM2_Alg.NULL, (uint)TPM2_Alg.NULL);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            rc = device.UnloadHandle(blob);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);
        }
    void MakeKeyFramesAndJointData()
    {
        var keyBlobs = animation.keyFrames;

        keyframes = new List <List <KeyFrame> >(10);
        for (int i = 0; i < 10; i++)
        {
            keyframes.Add(new List <KeyFrame>());
        }
        jointData = new JointData[numJoints];
        List <QJoint> indexedJoints = new List <QJoint>(numJoints);

        for (int i = 0; i < numJoints; i++)
        {
            indexedJoints.Add(null);
        }
        foreach (KeyValuePair <string, KeyBlob> kv in keyBlobs)
        {
            QJoint curJoint = FindJointByName(kv.Key);
            int    curIdx   = curJoint.index;
            indexedJoints[curIdx] = curJoint;
        }
        for (int i = 0; i < numJoints; i++)
        {
            QJoint  joint = indexedJoints[i];
            KeyBlob blob  = keyBlobs[joint.name];

            int[] jointDataArgs = new int[20];

            for (int j = 0; j < 10; j++)
            {
                string attribName = "m_LocalPosition.x";
                switch (j)
                {
                case (1):
                    attribName = "m_LocalPosition.y";
                    break;

                case (2):
                    attribName = "m_LocalPosition.z";
                    break;

                case (3):
                    attribName = "m_LocalRotation.x";
                    break;

                case (4):
                    attribName = "m_LocalRotation.y";
                    break;

                case (5):
                    attribName = "m_LocalRotation.z";
                    break;

                case (6):
                    attribName = "m_LocalRotation.w";
                    break;

                case (7):
                    attribName = "m_LocalScale.x";
                    break;

                case (8):
                    attribName = "m_LocalScale.y";
                    break;

                case (9):
                    attribName = "m_LocalScale.z";
                    break;
                }
                SortedList <float, ScalarFrame> frames = blob.keyedAttributes[attribName].values;
                jointDataArgs[j * 2]     = keyframes[j].Count;
                jointDataArgs[j * 2 + 1] = frames.Count;
                for (int k = 0; k < frames.Count; k++)
                {
                    float       time     = frames.Keys[k];
                    ScalarFrame frame    = frames.Values[k];
                    KeyFrame    newFrame = new KeyFrame(time, frame.value, frame.inTangent, frame.outTangent);
                    keyframes[j].Add(newFrame);
                }
            }
            int       numChildren = NumChildren(i);
            Matrix4x4 bindPose    = bindTransforms[i];//.inverse;
            jointData[i] = new JointData(jointDataArgs, numChildren, bindPose);
        }
    }
Beispiel #7
0
        /// <summary>
        /// rips apart rawKey into public byte [] for DsaParameters class
        /// </summary>
        public Dsa(byte [] rawKey)
        {
            this.rawKey = rawKey; //336 //444

            pks = new PUBLICKEYSTRUC();
            pks.bType = rawKey[0]; //7 //6
            pks.bVersion = rawKey[1]; //2
            pks.reserved = BitConverter.ToUInt16(rawKey, 2); //0
            pks.aiKeyAlg = BitConverter.ToUInt32(rawKey, 4); //8704

            kb = (KeyBlob) pks.bType; //private //public
            c = (Calg) pks.aiKeyAlg; //DSS_SIGN

            if(kb != KeyBlob.PUBLICKEYBLOB && kb != KeyBlob.PRIVATEKEYBLOB)
                throw new Exception("unsupported blob type");

            dpk = new DSSPUBKEY();
            //PRIV This must always be set to 0x32535344. the ASCII encoding of DSS2.
            //PUB This must always be set to 0x31535344, the ASCII encoding of DSS1.
            dpk.magic = BitConverter.ToUInt32(rawKey, 8); //844321604 //827544388
            //Number of bits in the DSS key BLOB's prime, P.
            dpk.bitlen = BitConverter.ToUInt32(rawKey, 12); //1024
            uint byteLen = dpk.bitlen / 8; //128

            this.SetSizeAndPosition(dpk.bitlen);

            bool revBytes = true;
            P = Format.GetBytes(this.rawKey, pPos, pLen, revBytes);
            Q = Format.GetBytes(this.rawKey, qPos, qLen, revBytes);
            G = Format.GetBytes(this.rawKey, gPos, gLen, revBytes);
            if(kb == KeyBlob.PRIVATEKEYBLOB)
            {
                X = Format.GetBytes(this.rawKey, xyPos, xLen, revBytes);
                PgenCounter = Format.GetBytes(this.rawKey, xPgenCounterPos, pgenCounterLen, revBytes);
                Seed = Format.GetBytes(this.rawKey, xSeedPos, seedLen, revBytes);
            }
            if(kb == KeyBlob.PUBLICKEYBLOB)
            {
                Y = Format.GetBytes(this.rawKey, xyPos, yLen, revBytes);
                PgenCounter = Format.GetBytes(this.rawKey, yPgenCounterPos, pgenCounterLen, revBytes);
                Seed = Format.GetBytes(this.rawKey, ySeedPos, seedLen, revBytes);
            }

            ds = new DSSSEED();
            byte [] baPcTemp = new byte[4];
            Buffer.BlockCopy(PgenCounter, 0, baPcTemp, 0, PgenCounter.Length);
            ds.counter = (uint) BitConverter.ToInt32(baPcTemp, 0);
            ds.seed = (byte[]) Seed.Clone();

            Int64 bij = 0;
            Int64 bip = BitConverter.ToInt64(P, 0);
            Int64 biq = BitConverter.ToInt64(Q, 0);

            bij = (bip - 1) / biq;
            byte [] baJ = BitConverter.GetBytes(bij);
            int len = baJ.Length;
            int rem = (len % 4); //seems to be 4 byte blocks for J?
            int pad = 0;
            if(rem != 0)
            {
                pad = 4 - rem;
                len = len + pad;
            }
            this.J = new byte[len];
            Array.Copy(baJ, 0, this.J, pad, baJ.Length);
        }
Beispiel #8
0
        public void BuildRawKey(bool privateKey)
        {
            //build up rawKey byte[]
            uint dsaMagic = 0;
            uint caSize = 0;
            uint bitLen = (uint) this.P.Length * 8;
            this.SetSizeAndPosition(bitLen);

            if(privateKey == true)
            {
                kb = KeyBlob.PRIVATEKEYBLOB;
                caSize = privByteLen; //336
                dsaMagic = 0x32535344; //ASCII encoding of "DSS2"
            }
            else //public
            {
                kb = KeyBlob.PUBLICKEYBLOB;
                caSize = pubByteLen; //444
                dsaMagic = 0x31535344; //ASCII encoding of "DSS1"
            }

            rawKey = new byte[caSize];

            //PUBLICKEYSTRUC
            rawKey[0] = (byte) kb; //bType
            rawKey[1] = (byte) 2; //bVersion
            //reserved 2,3
            c = Calg.DSS_SIGN;
            byte [] baKeyAlg = BitConverter.GetBytes((uint)c); //aiKeyAlg
            Buffer.BlockCopy(baKeyAlg, 0, rawKey, 4, 4);

            pks = new PUBLICKEYSTRUC();
            pks.bType = rawKey[0];
            pks.bVersion = rawKey[1];
            pks.reserved = BitConverter.ToUInt16(rawKey, 2);
            pks.aiKeyAlg = BitConverter.ToUInt32(rawKey, 4);

            //DSSPUBKEY
            byte [] baMagic = BitConverter.GetBytes(dsaMagic);//magic
            Buffer.BlockCopy(baMagic, 0, rawKey, 8, 4);
            byte [] baBitlen = BitConverter.GetBytes(bitLen);//bitlen
            Buffer.BlockCopy(baBitlen, 0, rawKey, 12, 4);

            dpk = new DSSPUBKEY();
            dpk.magic = BitConverter.ToUInt32(rawKey, 8);
            dpk.bitlen = BitConverter.ToUInt32(rawKey, 12);
            uint byteLen = dpk.bitlen / 8;

            bool revBytes = true;
            Format.SetBytes(this.rawKey, pPos, pLen, this.P, revBytes);
            Format.SetBytes(this.rawKey, qPos, qLen, this.Q, revBytes);
            Format.SetBytes(this.rawKey, gPos, gLen, this.G, revBytes);
            if(privateKey == true)
            {
                Format.SetBytes(this.rawKey, xyPos, xLen, this.X, revBytes);
                Format.SetBytes(this.rawKey, xPgenCounterPos, pgenCounterLen, this.PgenCounter, revBytes);
                Format.SetBytes(this.rawKey, xSeedPos, seedLen, this.Seed, revBytes);
                //this.Y = null;
            }
            else //public
            {
                Format.SetBytes(this.rawKey, xyPos, yLen, this.Y, revBytes);
                Format.SetBytes(this.rawKey, yPgenCounterPos, pgenCounterLen, this.PgenCounter, revBytes);
                Format.SetBytes(this.rawKey, ySeedPos, seedLen, this.Seed, revBytes);
                this.X = null;
            }

            ds = new DSSSEED();
            byte [] baPcTemp = new byte[4];
            Buffer.BlockCopy(PgenCounter, 0, baPcTemp, 0, PgenCounter.Length);
            //Array.Reverse(baPcTemp, 0, baPcTemp.Length);
            ds.counter = (uint) BitConverter.ToInt32(baPcTemp, 0);
            ds.seed = (byte[]) Seed.Clone();

            //nowhere to put J
            //this.J = null;
        }
Beispiel #9
0
        /// <summary>
        /// rips apart rawKey into public byte [] for RsaParameters class
        /// </summary>
        public Rsa(byte [] rawKey)
        {
            this.rawKey = rawKey; //596

            pks = new PUBLICKEYSTRUC();
            pks.bType = rawKey[0]; //7
            pks.bVersion = rawKey[1]; //2
            pks.reserved = BitConverter.ToUInt16(rawKey, 2); //0
            pks.aiKeyAlg = BitConverter.ToUInt32(rawKey, 4); //41984

            kb = (KeyBlob) pks.bType; //PRIVATE
            c = (Calg) pks.aiKeyAlg; //RSA_KEYX

            if(kb != KeyBlob.PUBLICKEYBLOB && kb != KeyBlob.PRIVATEKEYBLOB)
                throw new Exception("unsupported blob type");

            rpk = new RSAPUBKEY();
            rpk.magic = BitConverter.ToUInt32(rawKey, 8); //843141970
            rpk.bitlen = BitConverter.ToUInt32(rawKey, 12); //1024
            rpk.pubexp = BitConverter.ToUInt32(rawKey, 16); //65537
            uint byteLen = rpk.bitlen / 8; //128

            this.SetSizeAndPosition(rpk.bitlen);

            //public
            Modulus = Format.GetBytes(this.rawKey, modulusPos, modulusLen, true);
            Exponent = Format.GetBytes(this.rawKey, exponentPos, exponentLen, true);
            //private
            if(kb == KeyBlob.PRIVATEKEYBLOB)
            {
                this.P = Format.GetBytes(this.rawKey, prime1Pos, prime1Len, true);
                this.Q = Format.GetBytes(this.rawKey, prime2Pos, prime2Len, true);
                this.DP = Format.GetBytes(this.rawKey, exponent1Pos, exponent1Len, true);
                this.DQ = Format.GetBytes(this.rawKey, exponent2Pos, exponent2Len, true);
                this.InverseQ = Format.GetBytes(this.rawKey, coefficientPos, coefficientLen, true);
                this.D = Format.GetBytes(this.rawKey, privateExponentPos, privateExponentLen, true);
            }
            else
            {
                this.P = null;
                this.Q = null;
                this.DP = null;
                this.DQ = null;
                this.InverseQ = null;
                this.D = null;
            }
        }
Beispiel #10
0
        public void BuildRawKey(bool privateKey)
        {
            //build up rawKey byte[]
            uint rsaMagic = 0;
            int caSize = 0;
            uint bitLen = (uint) this.Modulus.Length * 8;

            if(privateKey == true)
            {
                kb = KeyBlob.PRIVATEKEYBLOB;
                caSize = 20 + (9 * ((int)bitLen / 16));
                rsaMagic = 0x32415352; //ASCII encoding of "RSA2"
            }
            else //public
            {
                kb = KeyBlob.PUBLICKEYBLOB;
                caSize = 20 + ((int)bitLen / 8);
                rsaMagic = 0x31415352; //ASCII encoding of "RSA1"
            }

            rawKey = new byte[caSize];

            //PUBLICKEYSTRUC
            rawKey[0] = (byte) kb; //bType
            rawKey[1] = (byte) 2; //bVersion
            //reserved 2,3
            c = Calg.RSA_KEYX;
            byte [] baKeyAlg = BitConverter.GetBytes((uint)c);//aiKeyAlg
            Buffer.BlockCopy(baKeyAlg, 0, rawKey, 4, 4);

            pks = new PUBLICKEYSTRUC();
            pks.bType = rawKey[0];
            pks.bVersion = rawKey[1];
            pks.reserved = BitConverter.ToUInt16(rawKey, 2);
            pks.aiKeyAlg = BitConverter.ToUInt32(rawKey, 4);

            //RSAPUBKEY
            byte [] baMagic = BitConverter.GetBytes(rsaMagic);//magic
            Buffer.BlockCopy(baMagic, 0, rawKey, 8, 4);
            byte [] baBitlen = BitConverter.GetBytes(bitLen);//bitlen
            Buffer.BlockCopy(baBitlen, 0, rawKey, 12, 4);

            this.SetSizeAndPosition(bitLen);
            Format.SetBytes(this.rawKey, exponentPos, exponentLen, this.Exponent, true); //pubexp

            rpk = new RSAPUBKEY();
            rpk.magic = BitConverter.ToUInt32(rawKey, 8);
            rpk.bitlen = BitConverter.ToUInt32(rawKey, 12);
            rpk.pubexp = BitConverter.ToUInt32(rawKey, 16);
            uint byteLen = rpk.bitlen / 8;

            //public
            Format.SetBytes(this.rawKey, modulusPos, modulusLen, this.Modulus, true);
            Format.SetBytes(this.rawKey, exponentPos, exponentLen, this.Exponent, true);
            //private
            if(privateKey == true)
            {
                Format.SetBytes(this.rawKey, prime1Pos, prime1Len, this.P, true);
                Format.SetBytes(this.rawKey, prime2Pos, prime2Len, this.Q, true);
                Format.SetBytes(this.rawKey, exponent1Pos, exponent1Len, this.DP, true);
                Format.SetBytes(this.rawKey, exponent2Pos, exponent2Len, this.DQ, true);
                Format.SetBytes(this.rawKey, coefficientPos, coefficientLen, this.InverseQ, true);
                Format.SetBytes(this.rawKey, privateExponentPos, privateExponentLen, this.D, true);
            }
            else
            {
                this.P = null;
                this.Q = null;
                this.DP = null;
                this.DQ = null;
                this.InverseQ = null;
                this.D = null;
            }
        }
Beispiel #11
0
        private void GenerateKey(string algorithm)
        {
            int      rc       = (int)Status.TPM_RC_SUCCESS;
            KeyBlob  blob     = new KeyBlob();
            Template template = new Template();

            byte[] blob_buffer = new byte[Device.MAX_KEYBLOB_BYTES];

            if (algorithm == "RSA")
            {
                rc = template.GetKeyTemplate_RSA((ulong)(
                                                     TPM2_Object.sensitiveDataOrigin |
                                                     TPM2_Object.userWithAuth |
                                                     TPM2_Object.decrypt |
                                                     TPM2_Object.sign |
                                                     TPM2_Object.noDA));
                Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);
            }
            else if (algorithm == "AES")
            {
                rc = template.GetKeyTemplate_Symmetric(256, TPM2_Alg.CTR, true, true);
                Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);
            }
            else
            {
                Console.WriteLine("Unexpected algorithm name!!!");
                Assert.Fail();
            }

            rc = device.CreateKey(blob, parent_key, template,
                                  "ThisIsMyStorageKeyAuth");
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            rc = device.LoadKey(blob, parent_key);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);

            rc = blob.GetKeyBlobAsBuffer(blob_buffer);
            if (rc > 0)
            {
                Array.Resize(ref blob_buffer, rc);
                if (algorithm == "RSA")
                {
                    generatedRSA = blob_buffer;
                }
                else if (algorithm == "AES")
                {
                    generatedAES = blob_buffer;
                }
                else
                {
                    Console.WriteLine("Unexpected algorithm name!");
                    return;
                }
                rc = (int)Status.TPM_RC_SUCCESS;
            }
            else
            {
                Console.WriteLine("wolfTPM2_GetKeyBlobAsBuffer() failed");
                rc = -1;
            }

            rc = device.UnloadHandle(blob);
            Assert.AreEqual((int)Status.TPM_RC_SUCCESS, rc);
        }
Beispiel #12
0
        public AnimationData MakeKeyFramesAndJointData(Mesh model)
        {
            int           numJoints = animation.jointNames.Count;
            var           keyBlobs  = animation.keyFrames;
            AnimationData result    = new AnimationData();

            result.jointData = new JointData[numJoints];
            result.keyframes = new List <KeyFrame> [10];
            for (int i = 0; i < 10; i++)
            {
                result.keyframes[i] = new List <KeyFrame>();
            }
            List <QJoint> indexedJoints = new List <QJoint>(numJoints);

            for (int i = 0; i < numJoints; i++)
            {
                indexedJoints.Add(null);
            }
            foreach (KeyValuePair <string, KeyBlob> kv in keyBlobs)
            {
                QJoint curJoint = FindJointByName(kv.Key);
                int    curidx   = curJoint.index;
                indexedJoints[curidx] = curJoint;
            }
            for (int i = 0; i < numJoints; i++)
            {
                QJoint  joint = indexedJoints[i];
                KeyBlob blob  = keyBlobs[joint.name];

                int[] jointDataArgs = new int[20];

                for (int j = 0; j < 10; j++)
                {
                    string attribName = "m_LocalPosition.x";
                    switch (j)
                    {
                    case (1):
                        attribName = "m_LocalPosition.y";
                        break;

                    case (2):
                        attribName = "m_LocalPosition.z";
                        break;

                    case (3):
                        attribName = "m_LocalRotation.x";
                        break;

                    case (4):
                        attribName = "m_LocalRotation.y";
                        break;

                    case (5):
                        attribName = "m_LocalRotation.z";
                        break;

                    case (6):
                        attribName = "m_LocalRotation.w";
                        break;

                    case (7):
                        attribName = "m_LocalScale.x";
                        break;

                    case (8):
                        attribName = "m_LocalScale.y";
                        break;

                    case (9):
                        attribName = "m_LocalScale.z";
                        break;
                    }
                    SortedList <float, ScalarFrame> frames = blob.keyedAttributes[attribName].values;
                    jointDataArgs[j * 2]     = result.keyframes[j].Count;
                    jointDataArgs[j * 2 + 1] = frames.Count;
                    for (int k = 0; k < frames.Count; k++)
                    {
                        float       time     = frames.Keys[k];
                        ScalarFrame frame    = frames.Values[k];
                        KeyFrame    newFrame = new KeyFrame(time, frame.value);
                        result.keyframes[j].Add(newFrame);
                    }
                }
                int       numChildren = NumChildren(i);
                Matrix4x4 bindPose    = model.bindposes[i];
                result.jointData[i] = new JointData(jointDataArgs, numChildren, bindPose);
            }
            return(result);
        }