如题, 我的最初的需求是这个样子的:系统支持WebService和SFTP两种方式的数据交换,现在已有了SFTP,要新增WS。 我们要求客户提交数据时,交对数据进行数据签名(基于RSA)。 所以想两咱试共用一对key, 但PuttyGen,生成的并不是一个标准的key格式。
现在我能所到的是, C#能处理PEM和XML格式的Key. 对于private key,PuttyGen就有一个工具将它转成pem(OpenSSL)格式的,这个OK;但对于public key,一直没找到如何转成能用的格式。
求大神!!!
我现在已可以生成pem格式的key,但还有问题
第一种方式,通过private key(pem) 生成 pem格式的public 这个已经测试通过
openssl rsa -in ~/.ssh/private.pem -pubout > ~/.ssh/publickkey.x509
第二种方式,用ssh-keygen把把PuttyGen 生成的public key转面ssh-keygen 格式的,然后再通过另一个命令,将它转成pem格式的。命令如下:
// convert public_putty.pub to public_openssl.pub
ssh-keygen -i -f ~/.ssh/public_putty.pub > ~/.ssh/public_openssl.pub
// convert openssl public key to pem format ssh-keygen -f ~/.ssh/public_openssl.pub -e -m pem >~/.ssh/public_pem.pem
这两种方式都能生成pem 格式的 public key.但结果不一样。。。第二种方式生成的key用不了。我是想用第二种方式的,因为这对key是由客户生成,他们只能给我们public key,总不能去要求客户帮我们转格式吧。 请大家帮我看下,第二种方式中,是不是哪里错了?我感觉最后那个命令可能错了
下面是一些各个相关的key
Putty生成的 private key
AAAAgCCkRto2vuhbDglO8RWsuxpBjoIi0BvytXvyRYwWKC1zFKrbeC80qO5yzRnz /GgepgU2JvoKcAGAwkNwTnjv/90xAIJfwJjNZiWYWqKjUYOddzN2gX+0w95S7wAs cRS/GcyVdmxHN/1snX9SS5IqpHIyeeF3psG3jYOPm70AxFaZAAAAQQDkgpYaSHrM 2ZGJUAMs4C5WWF3+ZP/vuZV2TpAd7/hKVJTQfZjEBY2c1bgaWLoF98FPvVbJo/fA 1e2lnjf1kjczAAAAQQDBSm9BeqEcsgXE8MsIXqiAFLFSTFvmQ8Rp0WaWEzF1CcqS 8iWZyNIYeNe+EJIWKxEtJgpvOdyRgm5ssJ9TT29TAAAAQQDkYVaYqYc/2OYEopIJ G5tAiGZoUjjQ3lKt0560kIPyQvWPJZDjnMnPIKj16Sgom728JER3uQ60pB1llCx4 vMLz
Putty生成的publc key(整个文本)
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-20151216"
AAAAB3NzaC1yc2EAAAABJQAAAIEArIjkOEXxFU8BDKFDcpEBisg6ZrgC3N5RjyUm
dr5CFM3/hxpWsF987F7OZJvtAcaSG4vyl1u9vs0nZHYxEYbat1+rJDFPaCc5y7yy
Kd2kjoR1aHnwI2zkFZZ8957rKbF5Bnlz+rGtLYWznotmdUasm9DVUh8GHWWyE3cY
UJYUAok=
---- END SSH2 PUBLIC KEY ----
Putty 转换生成的pem 格式的private key
MIICWwIBAAKBgQCsiOQ4RfEVTwEMoUNykQGKyDpmuALc3lGPJSZ2vkIUzf+HGlaw X3zsXs5km+0BxpIbi/KXW72+zSdkdjERhtq3X6skMU9oJznLvLIp3aSOhHVoefAj bOQVlnz3nuspsXkGeXP6sa0thbOei2Z1Rqyb0NVSHwYdZbITdxhQlhQCiQIBJQKB gCCkRto2vuhbDglO8RWsuxpBjoIi0BvytXvyRYwWKC1zFKrbeC80qO5yzRnz/Gge pgU2JvoKcAGAwkNwTnjv/90xAIJfwJjNZiWYWqKjUYOddzN2gX+0w95S7wAscRS/ GcyVdmxHN/1snX9SS5IqpHIyeeF3psG3jYOPm70AxFaZAkEA5IKWGkh6zNmRiVAD LOAuVlhd/mT/77mVdk6QHe/4SlSU0H2YxAWNnNW4Gli6BffBT71WyaP3wNXtpZ43 9ZI3MwJBAMFKb0F6oRyyBcTwywheqIAUsVJMW+ZDxGnRZpYTMXUJypLyJZnI0hh4 174QkhYrES0mCm853JGCbmywn1NPb1MCQQCBseZ9nsI86jAB03dsfzzk5gvVk0Un MfriSEP1UNkHl8oVd7eR2aNm2io4d4ws5pBP2ipWxNi5jizvS/Y/RSY/AkA+sFtv LrDLCU36rvW9hnvWg0Btt+Z0Mad8Q+nre9iwVjPcoY+nf2a71CpLev7ybtUjZkiS xqhmiyq7d42eeqClAkEA5GFWmKmHP9jmBKKSCRubQIhmaFI40N5SrdOetJCD8kL1 jyWQ45zJzyCo9ekoKJu9vCREd7kOtKQdZZQseLzC8w==
第一种方式中,根据 private key(pem)生成的 public key(pem):正确
MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCsiOQ4RfEVTwEMoUNykQGKyDpm uALc3lGPJSZ2vkIUzf+HGlawX3zsXs5km+0BxpIbi/KXW72+zSdkdjERhtq3X6sk MU9oJznLvLIp3aSOhHVoefAjbOQVlnz3nuspsXkGeXP6sa0thbOei2Z1Rqyb0NVS HwYdZbITdxhQlhQCiQIBJQ==
第二种方式,第一步,根据public key(putty)生成的public key(openssl)(整个文本)
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEArIjkOEXxFU8BDKFDcpEBisg6ZrgC3N5RjyUmdr5CFM3/hxpWsF987F7OZJvtAcaSG4vyl1u9vs0nZHYxEYbat1+rJDFPaCc5y7yyKd2kjoR1aHnwI2zkFZZ8957rKbF5Bnlz+rGtLYWznotmdUasm9DVUh8GHWWyE3cYUJYUAok=
第二种方式,第二步,根据public key(openssl) 生成的public key(pem)
MIGHAoGBAKyI5DhF8RVPAQyhQ3KRAYrIOma4AtzeUY8lJna+QhTN/4caVrBffOxe
zmSb7QHGkhuL8pdbvb7NJ2R2MRGG2rdfqyQxT2gnOcu8sindpI6EdWh58CNs5BWW
fPee6ymxeQZ5c/qxrS2Fs56LZnVGrJvQ1VIfBh1lshN3GFCWFAKJAgEl
补充二:问题已解决
原来是自己C#那套load public key的方法,并不适合这种pem格式的。 将第二方式中的,第二个命令中的 -pem 改成 -pkcs8就OK了。随便发下那套load rsa key类(从网上找来的)。
public class RSACommonHelper { public static string SignData(string privateKey, string input) { RSACryptoServiceProvider key = CreateRsaProviderFromPrivateKey(privateKey); RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(key); formatter.SetHashAlgorithm("MD5"); byte[] inputArr = Convert.FromBase64String(input); byte[] singnatureArr = formatter.CreateSignature(inputArr); return Convert.ToBase64String(singnatureArr); } public static bool VerifyData(string publicKey, string expectStr, string signatureStr) { try { RSACryptoServiceProvider key = CreateRsaProviderFromPublicKey(publicKey); RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key); deformatter.SetHashAlgorithm("MD5"); byte[] expectArr = Convert.FromBase64String(expectStr); byte[] rgbSignature = Convert.FromBase64String(signatureStr); if (deformatter.VerifySignature(expectArr, rgbSignature)) { return true; } return false; } catch { return false; } } public static string GetHash(string m_strSource) { HashAlgorithm algorithm = HashAlgorithm.Create("MD5"); byte[] bytes = Encoding.GetEncoding("UTF-8").GetBytes(m_strSource); byte[] inArray = algorithm.ComputeHash(bytes); return Convert.ToBase64String(inArray); } private static RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey) { var privateKeyBits = System.Convert.FromBase64String(privateKey); var RSA = new RSACryptoServiceProvider(); var RSAparams = new RSAParameters(); using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))) { byte bt = 0; ushort twobytes = 0; twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) binr.ReadByte(); else if (twobytes == 0x8230) binr.ReadInt16(); else throw new Exception("Unexpected value read binr.ReadUInt16()"); twobytes = binr.ReadUInt16(); if (twobytes != 0x0102) throw new Exception("Unexpected version"); bt = binr.ReadByte(); if (bt != 0x00) throw new Exception("Unexpected value read binr.ReadByte()"); RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.D = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.P = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr)); RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr)); } RSA.ImportParameters(RSAparams); return RSA; } private static int GetIntegerSize(BinaryReader binr) { byte bt = 0; byte lowbyte = 0x00; byte highbyte = 0x00; int count = 0; bt = binr.ReadByte(); if (bt != 0x02) return 0; bt = binr.ReadByte(); if (bt == 0x81) count = binr.ReadByte(); else if (bt == 0x82) { highbyte = binr.ReadByte(); lowbyte = binr.ReadByte(); byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; count = BitConverter.ToInt32(modint, 0); } else { count = bt; } while (binr.ReadByte() == 0x00) { count -= 1; } binr.BaseStream.Seek(-1, SeekOrigin.Current); return count; } private static RSACryptoServiceProvider CreateRsaProviderFromPublicKey(string publicKeyString) { // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; byte[] x509key; byte[] seq = new byte[15]; int x509size; x509key = Convert.FromBase64String(publicKeyString); x509size = x509key.Length; // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ using (MemoryStream mem = new MemoryStream(x509key)) { using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading { byte bt = 0; ushort twobytes = 0; twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8230) binr.ReadInt16(); //advance 2 bytes else return null; seq = binr.ReadBytes(15); //read the Sequence OID if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct return null; twobytes = binr.ReadUInt16(); if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8203) binr.ReadInt16(); //advance 2 bytes else return null; bt = binr.ReadByte(); if (bt != 0x00) //expect null byte next return null; twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) binr.ReadByte(); //advance 1 byte else if (twobytes == 0x8230) binr.ReadInt16(); //advance 2 bytes else return null; twobytes = binr.ReadUInt16(); byte lowbyte = 0x00; byte highbyte = 0x00; if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus else if (twobytes == 0x8202) { highbyte = binr.ReadByte(); //advance 2 bytes lowbyte = binr.ReadByte(); } else return null; byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order int modsize = BitConverter.ToInt32(modint, 0); int firstbyte = binr.PeekChar(); if (firstbyte == 0x00) { //if first byte (highest order) of modulus is zero, don't include it binr.ReadByte(); //skip this null byte modsize -= 1; //reduce modulus buffer size by 1 } byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data return null; int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) byte[] exponent = binr.ReadBytes(expbytes); // ------- create RSACryptoServiceProvider instance and initialize with public key ----- RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); RSAParameters RSAKeyInfo = new RSAParameters(); RSAKeyInfo.Modulus = modulus; RSAKeyInfo.Exponent = exponent; RSA.ImportParameters(RSAKeyInfo); return RSA; } } } private static bool CompareBytearrays(byte[] a, byte[] b) { if (a.Length != b.Length) return false; int i = 0; foreach (byte c in a) { if (c != b[i]) return false; i++; } return true; } }
请看支付宝SDK