二次元手游活动社区

曾差点威胁到 QQ 的 UC及校友录,没了,UC的加解密算法

9344

1 腾讯的危机-收费注册

2002年7月,第一个版本的UC上线。此时,腾讯正在经历戏剧性的艰难时刻,马化腾尚未找到盈利点,原本打算100万把QQ卖给“车库老板”——深圳电信局,但对方只出60万,没有谈妥。

腾讯心想,怎么也得用QQ赚点钱才行。史无前例的QQ收费注册因此来临, 顶着漫天骂声,腾讯于2002年3月宣布将推出“QQ行靓号地带”业务,出售QQ号码使用权,选择该项服务,能获得5位、6位、8位靓号以及生日号码的使用权,并享用QQ会员功能。到9月,“QQ行”号码正式向全国用户发售,每月收费2元,免费号码和一次性号码申请基本停止发放。

腾讯的收费战略果然把“竞争之狼”引了进来。 就在“QQ行”号码正式发售的9月,一家叫朗玛的创业公司推出朗玛UC客户端,它以独特的场景聊天、动作语言、动画图释等众多新颖的功能赢得了用户的喜爱,在短短的3个月时间里注册用户数就突破800万,在线用户数超过3万。在朗玛UC面世的几个月里,几乎所有的门户网站不约而同地推出了自己的即时通信工具——网易泡泡、新浪聊聊吧、搜狐我找你、雅虎通、263的E话通、TOM的skype,市面上出现了30多款类似的产品,腾讯引爆了一场针对自己的围剿战。

到2003年6月,马化腾如梦初醒,决定重回免费之路。腾讯以“庆祝移动QQ三周岁生日”为名,宣布新开通移动QQ的用户,可以获得免费长期使用QQ号码一个。至此腾讯再次打开长期使用号码发放之门。两个月后,QQ重新开放免费注册。可是,群狼对腾讯的围攻之势已然生成,在之后的两年多里,腾讯不得不疲于应付。

2 郎码uc的崛起

作为QQ的免费替代品,朗玛UC的优点不少,最主要的是它跟QQ的界面做的最像,功能也最为全面和相似,是一个足够好的替代品。

在当时,网吧是人们接触互联网的主要渠道,不少网吧跟着QQ一起安装了朗玛UC。而UC号也跟QQ号一样成为抢注的对象。

QQ的许多会员功能,如建立团体/同学录(类似QQ群),好友分组上传,高级查找,在UC都可以免费用。当时有报道写道,众多网民的真实想法是“虽然QQ功能很多,但大多只有会员才能用上,与其在QQ做最底层的用户,不如到UC那里做不交钱的会员。”

面对竞争,QQ重新开放免费号码发放。

3 chinaren 的辉煌

4 校友录之争

UC诞生于2002年,由贵州朗玛信息技术公司开发制作。2001年起,由于腾讯 QQ 选择注册收费的道路,逐步停止用户免费注册,到 2002 年已经基本停止免费注册,一直免费的朗玛UC 迎来用户激增,2003年11月,UC的注册用户达到了8000万人,最高同时在线人数达30万人。

朗玛UC 在最高在线人数上的表现,一度让业界认为其已成为QQ 的强有力威胁,继限制免费注册后,2002年9月QQ 又推出QQ行号码,每月收取2元服务费,在收费上的一系列举动在行业观察者看来很可能是在伤害网友的感情。

而那一时期,朗玛UC 趁机发力,针对学生群体,创新推出了与IM结合的校友录、场景聊天等功能,每周保持一万人在线的增长速度。

当时的chinaren 成为热点, 为了和QQ抢占市场, UC加速校友录web端的开发。 校友录的设计和开发任务则落到产品总监刘玲身上。而系统的设计和开发则由刚掌握JAVA 语言的一位组长(后来的新昕科技CTO)带领几个技术和UI。

1 快速安排设计了从页面到系统的设计文档。

校友录系统设计校友录页面 单击“下一步”按钮,查找的结果就会显示出来,单击找到的目标班级,单击“下一步”会弹出该班级的详细信息,包括班级的ID号、成员数、管理员、班级名称、班级简介等(如图2)。

2 客户端加解密问题及解决

由于客户端程序和WEB系统分离,但共用一套算法, 当时负责客户端程序的技术是用C++ 写的, 最初编译成so动态加载, 结果出现时间稍长,系统必然崩溃的问题,迫不得已,将C++算法改写成Java,不仅速度超快,并且再也没有出现问题了,彻底解决问题。

import java.util.*;

public class EnDecrypt {

public static final int STARTKEY = 342;

public static final int MULTKEY = 51243;

public static final int ADDKEY = 31261;

public static String outString;

public EnDecrypt() {}

private static char[] CharToByteStr(char[] strInStr, int iInStrLen) {

outString = "";

for (int i = 0; i < iInStrLen; i++) {

String s_hex = Integer.toHexString(strInStr[i]);

outString += (s_hex.length() == 1) ? "0" + s_hex : s_hex;

}

return outString.toCharArray();

}

private static char[] PriEncrypt(char[] pcInStr, int alInstrLen,

int lStartKey, int lMultKey, int lAddKey) {

int i = 0;

System.out.println("PriEncrypt len=" + alInstrLen);

while (i < alInstrLen) {

pcInStr[i] = (char) (0x00ff & ( (pcInStr[i]) ^ (lStartKey >> 8)));

lStartKey = ( (short) pcInStr[i] + lStartKey) * lMultKey + lAddKey;

i++;

}

return pcInStr;

}

private static char[] PriDecrypt(char[] pcInStr, int li_len, int lStartKey,

int lMultKey, int lAddKey) {

System.out.println("\n PriDecrypt len=" + li_len);

int i = 0;

char cOriChar;

outString = "";

int j = 0;

while (i < li_len) {

cOriChar = pcInStr[i];

pcInStr[i] = (char) (0x00ff & ( (pcInStr[i]) ^ (lStartKey >> 8)));

if ( (int) pcInStr[i] >= 128) {

if (j % 2 == 1) {

byte[] b2 = new byte[2];

b2[0] = (byte) ( (int) pcInStr[i - 1] - 256);

b2[1] = (byte) ( (int) pcInStr[i] - 256);

outString += new String(b2);

}

j++;

}

else {

outString += pcInStr[i];

}

lStartKey = ( (short) cOriChar + lStartKey) * lMultKey + lAddKey;

i++;

}

return pcInStr;

}

private static char[] ByteToCharStr(char[] strInStr) {

char[] strOutStr = new char[strInStr.length / 2];

int iInStrLen = strInStr.length;

if ( (iInStrLen % 2) == 0) {

int j = 0;

for (int i = 0; i < iInStrLen; i += 2) {

int iTemp = Integer.parseInt(String.valueOf(strInStr[i]) +

String.valueOf(strInStr[i + 1]), 16);

strOutStr[j++] = (char) (0x00ff & iTemp);

} //for

}

else

System.out.println("err!");

return strOutStr;

}

//******************************************************************

//解密函数**********************************************************

public static int Decrypt(String strInStr) throws Exception { //解密

int iRet = 0;

if (strInStr == null || strInStr.trim().length() < 6)

return -2;

String preInStr = strInStr.substring(0, 6);

char[] charA = ByteToCharStr(preInStr.toCharArray()); // 用 ByteToCharStr 对前6位- > str0StrStart "3565e6" result=str0StrStart

char[] charB = PriDecrypt(charA, 3, STARTKEY, MULTKEY, ADDKEY); // input =str0StrStart

int lStartKey = Integer.parseInt(String.valueOf(charB)); // str0StrStart 将第一次 PriDecrypt 后的 str0StrStart - > lStartKey

int ul3FinaLen = strInStr.length() - 6;

int ulFinaLen = ul3FinaLen / 2;

String sTemp = strInStr.substring(6);

char[] charC = ByteToCharStr(sTemp.toCharArray());

char[] charD = PriDecrypt(charC, ulFinaLen, lStartKey, MULTKEY, ADDKEY); // input =str0StrStart

System.out.println("the decrypt result=" + outString);

return iRet;

}

//******************************************************************

//加密函数**********************************************************

public static int Encrypt(String strInStr) { //加密

int iRet = 0;

Random rd = new Random();

int lStartKey = rd.nextInt(743) + 256; // 产生三位随机数

char[] strStart = String.valueOf(lStartKey).toCharArray(); // 将三位随机数放到char数组中

int liStart = strStart.length; // 取出三位随机数数组长度

char[] charA = PriEncrypt(strStart, liStart, STARTKEY, MULTKEY, ADDKEY); // 对随机数第一次编码,返回char数组 A

int alInstrLen = sTr2Char(strInStr).length; // 将输入进行中文处理后的长度

char[] charB = PriEncrypt(sTr2Char(strInStr), alInstrLen, lStartKey,

MULTKEY, ADDKEY); // 对输入第二次编码,返回char数组 B

int ulOutStrLentemp = 3 + alInstrLen;

char[] charC = CharToByteStr(combineArray(charA, charB), alInstrLen + 3); // 将 A+B 后的char数组转成 byte ,同时结果为 outString

System.out.println("the encrypt result=" + outString);

iRet = 1;

return iRet;

}

private static char[] combineArray(char[] a, char[] b) { // 将 a+b 后返回数组

int len = a.length + b.length;

char ret[] = new char[len];

for (int i = 0; i < len; i++) {

if (i < a.length) {

ret[i] = a[i];

}

else {

ret[i] = b[i - a.length];

}

}

return ret;

}

//******************************************************************

private static char[] sTr2Char(String s) {

char[] c_str = s.toCharArray();

// 一个中文算两个字符,先算出总长度

int len = 0;

for (int i = 0; i < c_str.length; i++) {

len = ( (int) (c_str[i]) > 128) ? len + 2 : len + 1;

}

char[] c_ret = new char[len];

int j = 0;

for (int i = 0; i < c_str.length; i++) {

if ( (int) (c_str[i]) > 128) {

byte[] bytes = (String.valueOf(c_str[i])).getBytes();

c_ret[j] = (char) (bytes[0] + 256);

c_ret[j + 1] = (char) (bytes[1] + 256);

j++;

}

else {

c_ret[j] = c_str[i];

}

j++;

}

return c_ret;

}

public static void main(String[] argv) throws Exception {

EnDecrypt tests = new EnDecrypt();

tests.Encrypt("刘光昕a\n\0b刘光昕test刘光昕刘光昕刘光昕");

tests.Decrypt(outString);

System.out.println("result=" + outString);

System.out.println("刘光昕a\n\0b刘光昕test刘光昕刘光昕刘光昕".equals(outString));

//tests.Encrypt("happy new years ! ");

//tests.Decrypt(outString);

}

/* main(String[]) */

}

5 手机号注册网站查询

说起校友录,不的不提起手机查询注册过哪些网站,很多人会说上 reg007 这个网站查询。自己买了会员体验后,发现这个网站有两个不好的地方,一是要收费,二是查询的网站太少。

之后就又开始找有没有更好的解决办法,还真给找到了,今天就来和大家分享一个简单、免费更有效的方法。

一分钟就能查询出多达 几十 个你手机注册过的网站/App。

只需要简单几步。首先, 打开浏览器, 输入网址 : www.newx007.com 。

1 注册会员

2 登录进入,首先看到的是类似 hao123 的网址导航

可以查找某个省份的短信运营商

3 点击好友,查看好友列表

4 加好友(现在免费呀)

关键的最后一步,加完好友手机号,坐等1分钟, 好友注册的网站逐步显示出来

加完好友,不要着急, 后台系统正在进行全网扫描,一会功夫, 好友注册的网站全出来了 这可是个秘密, 不要问我为什么告诉你!

6 新浪uc的结局

2004年,朗玛UC 被新浪以首期1500万美元,总计不超3600万美元的代价收购,更名为新浪 UC。

新浪UC官方发布公告称,由于业务调整,新浪UC的PC客户端将于2017年5月10日下线,iOS与Android端也将于同日下线。公告建议,在UC客户端下线后用户使用微博聊天或私信群功能代替UC服务。

公告引得70后老板惊呼:「真的假的?」,搞得她好像真的还在用一样。

相关阅读: 比 REG007 更好用的查询手机注册网站的神器 清华大学团队:人脸识别爆出巨大丑闻,15分钟解锁19款手机

java aspectjrt AOP 用法
【疫情防控】疫情期间为什么要戴口罩?