C# RSA 加密
程序员文章站
2023-02-21 11:09:53
class Sign_verifySign { #region prepare string to sign. //example format: a=123&b=xxx&c (with sort) private static string encrypt(T body) { var mType ... ......
class sign_verifysign { #region prepare string to sign. //example format: a=123&b=xxx&c (with sort) private static string encrypt<t>(t body) { var mtype = body.gettype(); var props = mtype.getproperties().orderby(x => x.name).toarray(); stringbuilder sb = new stringbuilder(); foreach (var p in props) { if (p.name != "sign" && p.name != "signtype" && p.getvalue(body, null) != null && p.getvalue(body, null).tostring() != "") { sb.append(string.format("{0}={1}&", p.name, p.getvalue(body, null))); } } var tmp = sb.tostring(); return tmp.substring(0, tmp.length - 1); } #endregion #region sign public static string sign(string content, string privatekey, string input_charset) { byte[] data = encoding.getencoding(input_charset).getbytes(content); rsacryptoserviceprovider rsa = decodepemprivatekey(privatekey); sha1 sh = new sha1cryptoserviceprovider(); byte[] signdata = rsa.signdata(data, sh); //get base64string -> ascii byte[] var base64tobyte = encoding.ascii.getbytes(convert.tobase64string(signdata)); string signresult = bitconverter.tostring(base64tobyte).replace("-", string.empty); return signresult; } private static rsacryptoserviceprovider decodepemprivatekey(string pemstr) { byte[] pkcs8privatekey; pkcs8privatekey = convert.frombase64string(pemstr); if (pkcs8privatekey != null) { rsacryptoserviceprovider rsa = decodeprivatekeyinfo(pkcs8privatekey); return rsa; } else return null; } private static rsacryptoserviceprovider decodeprivatekeyinfo(byte[] pkcs8) { byte[] seqoid = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 }; byte[] seq = new byte[15]; memorystream mem = new memorystream(pkcs8); int lenstream = (int)mem.length; binaryreader binr = new binaryreader(mem); //wrap memory stream with binaryreader for easy reading byte bt = 0; ushort twobytes = 0; try { 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; bt = binr.readbyte(); if (bt != 0x02) return null; twobytes = binr.readuint16(); if (twobytes != 0x0001) return null; seq = binr.readbytes(15); //read the sequence oid if (!comparebytearrays(seq, seqoid)) //make sure sequence for oid is correct return null; bt = binr.readbyte(); if (bt != 0x04) //expect an octet string return null; bt = binr.readbyte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count if (bt == 0x81) binr.readbyte(); else if (bt == 0x82) binr.readuint16(); //------ at this stage, the remaining sequence should be the rsa private key byte[] rsaprivkey = binr.readbytes((int)(lenstream - mem.position)); rsacryptoserviceprovider rsacsp = decodersaprivatekey(rsaprivkey); return rsacsp; } catch (exception) {return null; } finally { binr.close(); } } 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; } private static rsacryptoserviceprovider decodersaprivatekey(byte[] privkey) { byte[] modulus, e, d, p, q, dp, dq, iq; // --------- set up stream to decode the asn.1 encoded rsa private key ------ memorystream mem = new memorystream(privkey); binaryreader binr = new binaryreader(mem); //wrap memory stream with binaryreader for easy reading byte bt = 0; ushort twobytes = 0; int elems = 0; try { 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(); if (twobytes != 0x0102) //version number return null; bt = binr.readbyte(); if (bt != 0x00) return null; //------ all private key components are integer sequences ---- elems = getintegersize(binr); modulus = binr.readbytes(elems); elems = getintegersize(binr); e = binr.readbytes(elems); elems = getintegersize(binr); d = binr.readbytes(elems); elems = getintegersize(binr); p = binr.readbytes(elems); elems = getintegersize(binr); q = binr.readbytes(elems); elems = getintegersize(binr); dp = binr.readbytes(elems); elems = getintegersize(binr); dq = binr.readbytes(elems); elems = getintegersize(binr); iq = binr.readbytes(elems); // ------- create rsacryptoserviceprovider instance and initialize with public key ----- rsacryptoserviceprovider rsa = new rsacryptoserviceprovider(); rsaparameters rsaparams = new rsaparameters(); rsaparams.modulus = modulus; rsaparams.exponent = e; rsaparams.d = d; rsaparams.p = p; rsaparams.q = q; rsaparams.dp = dp; rsaparams.dq = dq; rsaparams.inverseq = iq; rsa.importparameters(rsaparams); return rsa; } catch (exception e) { return null; } finally { binr.close(); } } private static int getintegersize(binaryreader binr) { byte bt = 0; byte lowbyte = 0x00; byte highbyte = 0x00; int count = 0; bt = binr.readbyte(); if (bt != 0x02) //expect integer return 0; bt = binr.readbyte(); if (bt == 0x81) count = binr.readbyte(); // data size in next byte else if (bt == 0x82) { highbyte = binr.readbyte(); // data size in next 2 bytes lowbyte = binr.readbyte(); byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; count = bitconverter.toint32(modint, 0); } else { count = bt; // we already have the data size }while (binr.readbyte() == 0x00) { //remove high order zeros in data count -= 1; } binr.basestream.seek(-1, seekorigin.current); //last readbyte wasn't a removed zero, so back up a byte return count; } #endregion #region verifysign //onepay verify public static bool verifyfromhexascii(string sign, string publickey, string content, string charset) { string decsign = system.text.encoding.utf8.getstring(fromhexascii(sign)); return verify(content, decsign, publickey, charset); } public static byte[] fromhexascii(string s) { try { int len = s.length; if ((len % 2) != 0) throw new exception("hex ascii must be exactly two digits per byte."); int out_len = len / 2; byte[] out1 = new byte[out_len]; int i = 0; stringreader sr = new stringreader(s); while (i < out_len) { int val = (16 * fromhexdigit(sr.read())) + fromhexdigit(sr.read()); out1[i++] = (byte)val; } return out1; } catch (ioexception e) { throw new exception("ioexception reading from stringreader?!?!"); } } private static int fromhexdigit(int c) { if (c >= 0x30 && c < 0x3a) return c - 0x30; else if (c >= 0x41 && c < 0x47) return c - 0x37; else if (c >= 0x61 && c < 0x67) return c - 0x57; else throw new exception('\'' + c + "' is not a valid hexadecimal digit."); } public static bool verify(string content, string signedstring, string publickey, string input_charset) { signedstring = signedstring.replace("*", "+"); signedstring = signedstring.replace("-", "/"); return jijianverify(content, signedstring, publickey, input_charset); } public static bool jijianverify(string content, string signedstring, string publickey, string input_charset) { bool result = false; byte[] data = encoding.getencoding(input_charset).getbytes(content); byte[] data = convert.frombase64string(signedstring); rsaparameters parapub = convertfrompublickey(publickey); rsacryptoserviceprovider rsapub = new rsacryptoserviceprovider(); rsapub.importparameters(parapub); sha1 sh = new sha1cryptoserviceprovider(); result = rsapub.verifydata(data, sh, data); return result; } private static rsaparameters convertfrompublickey(string pemfileconent) { byte[] keydata = convert.frombase64string(pemfileconent); if (keydata.length < 162) { throw new argumentexception("pem file content is incorrect."); } rsakeyparameters publickeyparam = (rsakeyparameters)publickeyfactory.createkey(keydata); rsaparameters para = new rsaparameters(); para.modulus = publickeyparam.modulus.tobytearrayunsigned(); para.exponent = publickeyparam.exponent.tobytearrayunsigned(); return para; } #endregion }
上一篇: 妹子,好水量!