求助,C# RSA加密发送到服务器,返回密码错误

sinat_33576145 2016-02-11 08:22:19
用C#写一个客户端登录应用,分析登录页面的代码,登录逻辑如下:

1、从 "/login?act=getkey&_=" + (new Date).getTime() 获得公钥和hash值,返回的结果类似:
{
"hash" : "52c17e7b60a06c5b",
"key" : "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANe7Rmtt4U3mjPwixdxLrw9Yczkht8VE\nxECb05iKTGrlXcc3vXuDla1Vjs7EY2xD4se+pAaICeSqS+Rq7yVZKkcCAwEAAQ==\n-----END PUBLIC KEY-----\n"
}
其中的hash值会和密码字符串连接,然后加密。

页面RSA加密采用的是jsencrypt,地址为 http://travistidwell.com/jsencrypt/ ,关键代码为:
var s = new JSEncrypt;
s.setPublicKey(i.key), // i为上述json
a = s.encrypt(i.hash + a), // a为密码
最后得到的a为加密的密码。

2、POST登录数据到 /ajax/miniLogin/login ,POST的数据格式为:
userid=用户名&pwd=加密的密码&captcha=验证码&keep=1
使用Cookie中的sid值确定客户端。

POST完成后会返回一个json数据,错误信息如下:

ERROR_MAP = {
"-105": "验证码错误",
"-618": "昵称重复或含有非法字符",
"-619": "昵称不能小于3个字符或者大于30个字符",
"-620": "该昵称已被使用",
"-622": "Email已存在",
"-625": "密码错误次数过多",
"-626": "用户不存在",
"-627": "密码错误",
"-628": "密码不能小于6个字符或大于16个字符",
"-645": "昵称或密码过短",
"-646": "请输入正确的手机号",
"-647": "该手机已绑定另外一个账号",
"-648": "验证码发送失败",
"-652": "历史遗留问题,昵称与手机号重复,请联系管理员",
"-662": "加密后的密码已过期"
}

另附上具体的登录函数,供参考:
function init_login() {
$("#login-submit").click(function() {
var e = $(this),
t = $("#login-username").val(),
a = $("#login-passwd").val(),
n = $("#login-captcha").val(),
r = $("#keep-login").attr("checked") ? 1 : 0;
if (!e.hasClass("disabled") && !e.hasClass("loading")) {
if ($("#login .input").removeClass("ok error"), $("#login .message").text(""), "" == t) return $("#login .uname-row .input").error(), void $("#login .message[for=username]").text("手机号/邮箱不能为空");
if ("" == a) return $("#login .passwd-row .input").error(), void $("#login .message[for=passwd]").text("请输入密码");
e.addClass("loading"), $.getJSON("/login?act=getkey&_=" + (new Date).getTime(), function(i) {
if (i && i.error) $("#login .message[for=passwd]").text("服务端出现异常,请稍后重试");
else {
var s = new JSEncrypt;
s.setPublicKey(i.key), a = s.encrypt(i.hash + a), $.post("/ajax/miniLogin/login", {
userid: t,
pwd: a,
captcha: n,
keep: r
}, function(t) {
if (!t.status) {
var a = t.message.code;
if (-105 == a) {
var n = $("#login .captcha-row");
n.is(":visible") ? n.children(".input").addClass("error").next().text(ERROR_MAP[a]) : n.slideDown(), refresh_captcha(n.find(".captcha-img"))
} else -626 == a || -652 == a ? $("#login .uname-row").children(".input").addClass("error").next().text(ERROR_MAP[a]) : $("#login .passwd-row").children(".input").addClass("error").next().text(ERROR_MAP[a]);
return void e.removeClass("loading")
}
window.location.href = t.data.crossDomain
}, "json")
}
})
}
}), $("#login").on("keyup", "input", function(e) {
$(this).closest(".input").removeClass("error ok").next().text(""), 13 == e.keyCode && $("#login-submit").click()
})
}

对密码学不是很懂,C#采用的加密函数为:
public static string PemToXml(string pem)
{
if (pem.StartsWith("-----BEGIN PUBLIC KEY-----"))
{
//pem = pem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "");
return GetXmlRsaKey(pem, obj =>
{
var publicKey = (RsaKeyParameters)obj;
return DotNetUtilities.ToRSA(publicKey);
}, rsa => rsa.ToXmlString(false));
}


throw new InvalidKeyException("Unsupported PEM format...");
}


private static string GetXmlRsaKey(string pem, Func<object, RSA> getRsa, Func<RSA, string> getKey)
{
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms))
using (var sr = new StreamReader(ms))
{
sw.Write(pem);
sw.Flush();
ms.Position = 0;
var pr = new Org.BouncyCastle.OpenSsl.PemReader(sr);
object keyPair = pr.ReadObject();
using (RSA rsa = getRsa(keyPair))
{
var xml = getKey(rsa);
return xml;
}
}
}

/// <summary>
/// RSA加密
/// </summary>
/// <param name="publickey"></param>
/// <param name="content"></param>
/// <returns></returns>
public static string RSAEncrypt(string publickey, string content)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] cipherbytes;
rsa.FromXmlString(publickey);
cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(content), false);

return Convert.ToBase64String(cipherbytes);
}
大概逻辑为把从服务器上获取的公钥用 Org.BouncyCastle.OpenSsl.PemReader 和 DotNetUtilities.ToRSA 转换成 RSACryptoServiceProvider 可用的 xml 格式公钥,然后对 (hash+密码 ) 字符串进行加密,再POST到服务器,可是这样有时候可以成功登录,大部分时候返回
"-627": "密码错误"
因为对RSA加密算法不太了解,只能判断出加密的密码在服务器解密出来的结果不对,希望能得到这方面的指点,C#端应该怎么修改,非常感谢。
...全文
192 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
首先找出来 100% 出现问题的测试数据,确保你能够 100% 重现异常问题。而不是什么“有时候可以成功”。 确定你能重现异常之后,那么在你的服务器程序端进行调试,在断点上设置条件,使用 vs 捕获中断,进行调试。 你应该贴出你的调试画面,这样才能说明你的技术到底达到什么程度。如果你的代码都是“求”来的,恐怕很少有人有那个功夫。
秋的红果实 2016-02-12
  • 打赏
  • 举报
回复
是不是浏览器禁用了js,导致加密失败
sinat_33576145 2016-02-12
  • 打赏
  • 举报
回复
引用 1 楼 shingoscar 的回复:
[quote=引用 楼主 sinat_33576145 的回复:] 可是这样有时候可以成功登录,大部分时候返回
有时候?你确定不是传输路上出问题了?[/quote] 这。。。传输出问题就不会给我返回-627 -105之类的错误信息了
sinat_33576145 2016-02-12
  • 打赏
  • 举报
回复
引用 7 楼 shingoscar 的回复:
[quote=引用 2 楼 sinat_33576145 的回复:] [quote=引用 1 楼 shingoscar 的回复:] [quote=引用 楼主 sinat_33576145 的回复:] 可是这样有时候可以成功登录,大部分时候返回
有时候?你确定不是传输路上出问题了?[/quote] 这。。。传输出问题就不会给我返回-627 -105之类的错误信息了[/quote] 还有可能是指定的padding错误,我不知道应该用什么,去查下服务器这个api的说明 https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rsaencryptionpadding.aspx[/quote] 谢谢
Poopaye 2016-02-12
  • 打赏
  • 举报
回复
引用 2 楼 sinat_33576145 的回复:
[quote=引用 1 楼 shingoscar 的回复:] [quote=引用 楼主 sinat_33576145 的回复:] 可是这样有时候可以成功登录,大部分时候返回
有时候?你确定不是传输路上出问题了?[/quote] 这。。。传输出问题就不会给我返回-627 -105之类的错误信息了[/quote] 还有可能是指定的padding错误,我不知道应该用什么,去查下服务器这个api的说明 https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rsaencryptionpadding.aspx
sinat_33576145 2016-02-12
  • 打赏
  • 举报
回复
引用 4 楼 sp1234 的回复:
首先找出来 100% 出现问题的测试数据,确保你能够 100% 重现异常问题。而不是什么“有时候可以成功”。 确定你能重现异常之后,那么在你的服务器程序端进行调试,在断点上设置条件,使用 vs 捕获中断,进行调试。 你应该贴出你的调试画面,这样才能说明你的技术到底达到什么程度。如果你的代码都是“求”来的,恐怕很少有人有那个功夫。
服务器不是我的,要是我的,两边调一调,大概问题就猜出来了; 我不需要去说明我的技术达到什么程度,我发这里是希望能碰到一些曾经做过这种加密传输的人,给我指点一下我能少走一点弯路; 我不太了解RSA加密,看结果也知道我这边加密的数据到服务器那边解密出来不一样,说明我这种加密方法是不适合服务器的;其中出现了几次成功登录的情况,也就是服务器成功解密的情况,也许一个懂这方面的人,就能解释这种情况,我贴出来只是作为一个判断的参考。 如果你愿意帮我,就先仔细看一下再回复,否则谢谢,多说一句,不要随随便便扫了几句话就开始说教
sinat_33576145 2016-02-12
  • 打赏
  • 举报
回复
引用 3 楼 From_TaiWan 的回复:
是不是浏览器禁用了js,导致加密失败
不是用浏览器加密的
Poopaye 2016-02-11
  • 打赏
  • 举报
回复
引用 楼主 sinat_33576145 的回复:
可是这样有时候可以成功登录,大部分时候返回
有时候?你确定不是传输路上出问题了?

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧