Example #1
0
        public override void FromXmlString(string xmlString)
        {
            // ParseDocument does the nullcheck for us.
            XmlKeyHelper.ParseState state = XmlKeyHelper.ParseDocument(xmlString);

            byte[] n = ReadRequiredElement(ref state, nameof(RSAParameters.Modulus));
            byte[] e = ReadRequiredElement(ref state, nameof(RSAParameters.Exponent));

            int halfN = (n.Length + 1) / 2;

            // .NET Framework doesn't report any element other than Modulus/Exponent as required,
            // it just lets import fail if they're imbalanced.
            byte[]? p    = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.P), halfN);
            byte[]? q    = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.Q), halfN);
            byte[]? dp   = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.DP), halfN);
            byte[]? dq   = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.DQ), halfN);
            byte[]? qInv = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.InverseQ), halfN);
            byte[]? d    = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(RSAParameters.D), n.Length);

            RSAParameters keyParameters = new RSAParameters
            {
                Modulus  = n,
                Exponent = e,
                D        = d,
                P        = p,
                Q        = q,
                DP       = dp,
                DQ       = dq,
                InverseQ = qInv,
            };

            ImportParameters(keyParameters);
        }
Example #2
0
        public override void FromXmlString(string xmlString)
        {
            // ParseDocument does the nullcheck for us.
            XmlKeyHelper.ParseState state = XmlKeyHelper.ParseDocument(xmlString);

            byte[] p       = ReadRequiredElement(ref state, nameof(DSAParameters.P));
            byte[] q       = ReadRequiredElement(ref state, nameof(DSAParameters.Q));
            byte[] g       = ReadRequiredElement(ref state, nameof(DSAParameters.G), p.Length);
            byte[] y       = ReadRequiredElement(ref state, nameof(DSAParameters.Y), p.Length);
            byte[] j       = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(DSAParameters.J));
            byte[] seed    = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(DSAParameters.Seed));
            int    counter = 0;

            byte[] x = XmlKeyHelper.ReadCryptoBinary(ref state, nameof(DSAParameters.X), q.Length);

            if (seed != null)
            {
                byte[] counterBytes = ReadRequiredElement(ref state, CounterElementName);
                counter = XmlKeyHelper.ReadCryptoBinaryInt32(counterBytes);
            }

            DSAParameters dsaParameters = new DSAParameters
            {
                P       = p,
                Q       = q,
                G       = g,
                Y       = y,
                J       = j,
                Seed    = seed,
                Counter = counter,
                X       = x,
            };

            // Check for Counter without Seed after getting X, since that prevents an extra cycle in the
            // canonical element order.
            if (dsaParameters.Seed == null)
            {
                if (XmlKeyHelper.HasElement(ref state, CounterElementName))
                {
                    throw new CryptographicException(
                              SR.Format(
                                  SR.Cryptography_InvalidFromXmlString,
                                  nameof(DSA),
                                  nameof(DSAParameters.Seed)));
                }
            }

            ImportParameters(dsaParameters);
        }
Example #3
0
        private static byte[] ReadRequiredElement(
            ref XmlKeyHelper.ParseState state,
            string name,
            int sizeHint = -1)
        {
            byte[] ret = XmlKeyHelper.ReadCryptoBinary(ref state, name, sizeHint);

            if (ret == null)
            {
                throw new CryptographicException(
                          SR.Format(SR.Cryptography_InvalidFromXmlString, nameof(DSA), name));
            }

            return(ret);
        }
Example #4
0
        public override string ToXmlString(bool includePrivateParameters)
        {
            // The format of this output is based on the xmldsig ds:DSAKeyValue value, except
            // * It writes values as xml:base64Binary instead of ds:CryptoBinary
            //   * It doesn't strip off leading 0x00 byte values before base64
            // * It doesn't emit the output in a namespace
            // * When includePrivateParameters is true it writes an X element.
            //
            // These deviations are inherited from .NET Framework.

            // P is KeySizeInBytes long.
            // Q is 160 to 256 bits long, or 20 to 32 bytes.
            // G is the same size as P
            // Y is the same size as P
            // X is the same size as Q
            //
            // Each field gets base64 encoded (after dropping leading 0x00 bytes)
            // so P is (KeySizeInBytes + 2) / 3 * 4, then plus 7 (<P></P>)
            // (For 3072 that's 519 chars, for 1024 it's 179.)
            // Add in maximum-Q: (32 + 2) / 3 * 4 + 7 => 51
            // Then the "<DSAKeyValue></DSAKeyValue>" (27).
            // Grand total, 3 * P + 2 * Q + 27 => 1686 (3072) or 666 (1024).
            // KeySizeInBytes * 2 / 3 comes out to 2048 or 682, so call that good enough.

            // Rarely, keys will export the J or Seed values, and they may cause the
            // StringBuilder to need to grow.

            DSAParameters keyParameters = ExportParameters(includePrivateParameters);
            StringBuilder builder       = new StringBuilder((keyParameters.P.Length << 1) / 3);

            builder.Append("<DSAKeyValue>");
            XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.P), keyParameters.P, builder);
            XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.Q), keyParameters.Q, builder);
            XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.G), keyParameters.G, builder);
            XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.Y), keyParameters.Y, builder);

            if (keyParameters.J != null)
            {
                XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.J), keyParameters.J, builder);
            }

            if (keyParameters.Seed != null)
            {
                XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.Seed), keyParameters.Seed, builder);
                XmlKeyHelper.WriteCryptoBinary(CounterElementName, keyParameters.Counter, builder);
            }

            if (includePrivateParameters)
            {
                if (keyParameters.X == null)
                {
                    // NetFx compat when a 3rd party type lets X be null when
                    // includePrivateParameters is true
                    // (the exception would have been from Convert.ToBase64String)
                    throw new ArgumentNullException("inArray");
                }

                XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.X), keyParameters.X, builder);
            }

            builder.Append("</DSAKeyValue>");
            return(builder.ToString());
        }
Example #5
0
        public override string ToXmlString(bool includePrivateParameters)
        {
            // The format of this output is based on the xmldsig ds:RSAKeyValue value, except
            // * It writes values as xml:base64Binary instead of ds:CryptoBinary
            //   * It doesn't strip off leading 0x00 byte values before base64
            // * It doesn't emit the output in a namespace
            // * When includePrivateParameters is true it writes the private key elements.
            //   * D, P, Q, DP, DQ, InverseQ
            //
            // These deviations are inherited from .NET Framework.

            // For a public-only export, the output is like the following, but with no whitespace
            //
            //   <RSAKeyValue>
            //     <Modulus>[base64 modulus]</Modulus>
            //     <Exponent>AQAB</Exponent>
            //   </RSAKeyValue>
            //
            // (using the knowledge that 99.9(etc)% of RSA keys use the same exponent, 65537).
            // rsa.KeySize (bits) / 6 will produce a value just slightly smaller than needed:
            //
            //    KeySize | BytesReq | Div5 | Div6
            //    --------|----------|------|-----
            //      16384 |     2732 | 3276 | 2730
            //       2048 |      344 |  409 |  341
            //       1024 |      172 |  204 |  170
            //        512 |       88 |  102 |   85
            //
            // So just add 3 chars to the overhead.
            // The overhead, otherwise, is 65 chars, plus exponent's actual value.
            // While most keys are AQAB (0x010001) it's technically a variable.
            // CAPI has a limit of 32 bits. CNG-Win7 is unbounded, CNG-Win10 is 64-bits.
            // So call it 12 chars ((64/8 + 2) / 3 * 4).
            // 65 + 32 + 3 = 100.  Nice, round, number.
            //
            // For private keys, D is the same size as Modulus, and P/Q/DP/DQ/InverseQ are
            // each half the size of Modulus.  So their variable payload is 5 * (KeySize / 2 / 6).
            //
            // Their element tags add 58 extra characters, and sprinkle in another 3 each (18 total) for
            // base64 vs div6 padding, for a conditional overhead of 76 chars.

            int keySizeDiv6     = KeySize / 6;
            int initialCapacity = 100 + keySizeDiv6;

            if (includePrivateParameters)
            {
                initialCapacity += 76 + 5 * keySizeDiv6 / 2;
            }

            RSAParameters keyParameters = ExportParameters(includePrivateParameters);
            StringBuilder builder       = new StringBuilder(initialCapacity);

            builder.Append("<RSAKeyValue>");
            XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.Modulus), keyParameters.Modulus, builder);
            XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.Exponent), keyParameters.Exponent, builder);

            if (includePrivateParameters)
            {
                // Match .NET Framework field order.
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.P), keyParameters.P, builder);
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.Q), keyParameters.Q, builder);
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.DP), keyParameters.DP, builder);
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.DQ), keyParameters.DQ, builder);
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.InverseQ), keyParameters.InverseQ, builder);
                XmlKeyHelper.WriteCryptoBinary(nameof(RSAParameters.D), keyParameters.D, builder);
            }

            builder.Append("</RSAKeyValue>");
            return(builder.ToString());
        }