private static void WriteDSSSeed(DSAParameters dsaParameters, BinaryWriter bw) { if (dsaParameters.Seed == null || dsaParameters.Seed.Length == 0) { bw.Write(0xFFFFFFFF); // counter // seed[20] needs to be all 0xFF for (int i = 0; i < 20; i += sizeof(uint)) { bw.Write(0xFFFFFFFF); } } else { bw.Write((int)dsaParameters.Counter); bw.WriteReversed(dsaParameters.Seed); } }
/// <summary> /// Helper for DsaCryptoServiceProvider.ImportParameters() /// </summary> internal static byte[] ToKeyBlob(this DSAParameters dsaParameters) { const int NTE_BAD_DATA = unchecked((int)CryptKeyError.NTE_BAD_DATA); // Validate the DSA structure first // P and Q are required. Q is a 160 bit divisor of P-1. if (dsaParameters.P == null || dsaParameters.P.Length == 0 || dsaParameters.Q == null || dsaParameters.Q.Length != DSS_Q_LEN) throw NTE_BAD_DATA.ToCryptographicException(); // G is required. G is an element of Z_p if (dsaParameters.G == null || dsaParameters.G.Length != dsaParameters.P.Length) throw NTE_BAD_DATA.ToCryptographicException(); // If J is present, it should be less than the size of P: J = (P-1) / Q // This is only a sanity check. Not doing it here is not really an issue as CAPI will fail. if (dsaParameters.J != null && dsaParameters.J.Length >= dsaParameters.P.Length) throw NTE_BAD_DATA.ToCryptographicException(); // Y is present for V3 DSA key blobs, Y = g^j mod P if (dsaParameters.Y != null && dsaParameters.Y.Length != dsaParameters.P.Length) throw NTE_BAD_DATA.ToCryptographicException(); // The seed is always a 20 byte array if (dsaParameters.Seed != null && dsaParameters.Seed.Length != 20) throw NTE_BAD_DATA.ToCryptographicException(); bool isPrivate = (dsaParameters.X != null && dsaParameters.X.Length > 0); // The private key should be the same length as Q if (isPrivate && dsaParameters.X.Length != DSS_Q_LEN) throw NTE_BAD_DATA.ToCryptographicException(); uint bitLenP = (uint)dsaParameters.P.Length * 8; uint bitLenJ = dsaParameters.J == null ? 0 : (uint)dsaParameters.J.Length * 8; using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) { // Write out the BLOBHEADER bool isV3; WriteKeyBlobHeader(dsaParameters, bw, isPrivate, out isV3); // Write out the DSA key if (isV3) { // We need to build a key blob (DSSPUBKEY_VER3 or DSSPRIVKEY_VER3) as follows: // DWORD magic // DWORD bitlenP // DWORD bitlenQ // DWORD bitlenJ // DWORD bitlenX (if private) // DWORD counter (DSSSEED) // BYTE[20] seed (DSSSEED) // BYTE[lenP] P // BYTE[lenQ] Q // BYTE[lenP] G // BYTE[lenJ] J (optional) // BYTE[lenP] Y // BYTE[lenX] X (if private) bw.Write((int)(isPrivate ? DSS_PRIV_MAGIC_VER3 : DSS_PUB_MAGIC_VER3)); bw.Write((uint)(bitLenP)); bw.Write((uint)(dsaParameters.Q.Length * 8)); bw.Write((uint)(bitLenJ)); if (isPrivate) { bw.Write((uint)dsaParameters.X.Length * 8); } WriteDSSSeed(dsaParameters, bw); bw.WriteReversed(dsaParameters.P); bw.WriteReversed(dsaParameters.Q); bw.WriteReversed(dsaParameters.G); if (bitLenJ != 0) { bw.WriteReversed(dsaParameters.J); } bw.WriteReversed(dsaParameters.Y); if (isPrivate) { bw.WriteReversed(dsaParameters.X); } } else { // We need to build a key blob as follows: // DWORD magic (DSSPUBKEY) // DWORD bitlen (DSSPUBKEY) // BYTE[len] P // BYTE[DSS_Q_LEN] Q // BYTE[len] G // BYTE[20] X (if private) // BYTE[len] Y (if public) // DWORD counter (DSSSEED) // BYTE[20] seed (DSSSEED) bw.Write((int)(isPrivate ? DSS_PRIVATE_MAGIC : DSS_MAGIC)); bw.Write((uint)(bitLenP)); bw.WriteReversed(dsaParameters.P); bw.WriteReversed(dsaParameters.Q); bw.WriteReversed(dsaParameters.G); if (isPrivate) { bw.WriteReversed(dsaParameters.X); } else { bw.WriteReversed(dsaParameters.Y); } WriteDSSSeed(dsaParameters, bw); } bw.Flush(); byte[] key = ms.ToArray(); return key; } }
/// <summary> /// Helper for RsaCryptoServiceProvider.ImportParameters() /// </summary> internal static byte[] ToKeyBlob(this RSAParameters rsaParameters, int algId) { // The original FCall this helper emulates supports other algId's - however, the only algid we need to support is CALG_RSA_KEYX. We will not // port the codepaths dealing with other algid's. if (algId != CapiHelper.CALG_RSA_KEYX) throw new PlatformNotSupportedException(); const int NTE_BAD_DATA = unchecked((int)CryptKeyError.NTE_BAD_DATA); // Validate the RSA structure first. if (rsaParameters.Modulus == null) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.Exponent == null || rsaParameters.Exponent.Length > 4) throw NTE_BAD_DATA.ToCryptographicException(); int modulusLength = rsaParameters.Modulus.Length; int halfModulusLength = (modulusLength + 1) / 2; // We assume that if P != null, then so are Q, DP, DQ, InverseQ and D if (rsaParameters.P != null) { if (rsaParameters.P.Length != halfModulusLength) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.Q == null || rsaParameters.Q.Length != halfModulusLength) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.DP == null || rsaParameters.DP.Length != halfModulusLength) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.DQ == null || rsaParameters.DQ.Length != halfModulusLength) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.InverseQ == null || rsaParameters.InverseQ.Length != halfModulusLength) throw NTE_BAD_DATA.ToCryptographicException(); if (rsaParameters.D == null || rsaParameters.D.Length != modulusLength) throw NTE_BAD_DATA.ToCryptographicException(); } bool isPrivate = (rsaParameters.P != null && rsaParameters.P.Length != 0); MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); // Write out the BLOBHEADER bw.Write((byte)(isPrivate ? PRIVATEKEYBLOB : PUBLICKEYBLOB)); // BLOBHEADER.bType bw.Write((byte)(BLOBHEADER_CURRENT_BVERSION)); // BLOBHEADER.bVersion bw.Write((ushort)0); // BLOBHEADER.wReserved bw.Write((uint)algId); // BLOBHEADER.aiKeyAlg // Write the RSAPubKey header bw.Write((int)(isPrivate ? RSA_PRIV_MAGIC : RSA_PUB_MAGIC)); // RSAPubKey.magic bw.Write((uint)(modulusLength * 8)); // RSAPubKey.bitLen uint expAsDword = 0; for (int i = 0; i < rsaParameters.Exponent.Length; i++) { expAsDword <<= 8; expAsDword |= rsaParameters.Exponent[i]; } bw.Write((uint)expAsDword); // RSAPubKey.pubExp bw.WriteReversed(rsaParameters.Modulus); // Copy over the modulus for both public and private if (isPrivate) { bw.WriteReversed(rsaParameters.P); bw.WriteReversed(rsaParameters.Q); bw.WriteReversed(rsaParameters.DP); bw.WriteReversed(rsaParameters.DQ); bw.WriteReversed(rsaParameters.InverseQ); bw.WriteReversed(rsaParameters.D); } bw.Flush(); byte[] key = ms.ToArray(); return key; }