📄 soapsso.java
字号:
package jm.framework.msn.protocol.soap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import jm.framework.msn.util.Base64Coder;
import jm.framework.msn.util.Log;
/**
* 使用https进行Passport的验证过程,获得登陆必需的ticket和BinarySecret。 msnp15采用了SSO的方式进行认证。
* SSO,Single Sign-On,一次验证便可获取对应不同服务的ticket。 messengerclear.live.com:用于msn的认证
* messenger.msn.com:msn网页认证 contacts.msn.com:Contact server 的认证
* spaces.msn.com:msn spaces 的认证
*
* @author ishome
* @version 0.5.0.2
*/
public class SoapSSO {
// static
// {
// java.security.Security.addProvider(
// new com.sun.net.ssl.internal.ssl.Provider());
// System.setProperty( "java.protocol.handler.pkgs",
// "com.sun.net.ssl.internal.www.protocol" );
// }
/**
* RPS/SSO Authentication
*
* @param username
* 用户名
* @param password
* 密码
* @param policy
* 标识
* @param nonce
* 通知信息 在USR 6 SSO S
* 处获得服务器发送的Nonce,就是MBI_KEY_OLD后面的那一串;然后在USR 7 SSO S 处发
* @return String <ticket> <base64 encoded response structure>
*/
public static String getRPS(String username, String password, String policy, String nonce) {
final String server = "login.live.com";
final String page = "/RST.srf";
try {
// UTF-8 encode account and password
// account = URLEncoder.encode(account,"UTF-8");
// password = URLEncoder.encode(password,"UTF-8");
// create connection
SSLSocketFactory ssl = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) ssl.createSocket(server, 443);
// make input and output stream
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
// create buffers
StringBuffer buf = new StringBuffer();
String postXML = loadConfigMap(username, password, policy);
buf.append("POST " + page + " HTTP/1.1" + "\r\n");
buf.append("Accept: text/*" + "\r\n");
buf.append("User-Agent: LoginHelper/1.0" + "\r\n");
buf.append("Host: " + server + "\r\n");
buf.append("Content-Length: " + postXML.length() + "\r\n");
buf.append("Connection: Keep-Alive" + "\r\n");
buf.append("Cache-Control: no-cache" + "\r\n");
buf.append("\r\n");
buf.append(postXML.toString());
Log.info(" SSO >>>>> " + buf.toString());
// send
out.print(buf.toString());
out.flush();
// read
buf = new StringBuffer();
int Length = 0;
while (true) {
String str = in.readLine();
if (str != null && str.substring(0, 15).equals("Content-Length:")) {
String[] DataArray = str.split(" ");
Length = Integer.parseInt(DataArray[1]) + 2;
for (int i = 0; i < Length; i++) {
int c = in.read();
buf.append((char) c);
}
// get ticket and binarysecret
Log.info(" SSO <<<<< " + buf.toString());
if ("".equals(nonce)) {
return buf.toString();
} else {
return decode(buf.toString(), nonce);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* 获得钥匙
* @param data
* @param nonce
* @return
*/
public static String decode(String data, String nonce) {
data = data.substring(data.indexOf("messengerclear.live.com"));
String[] temp = data.split("BinarySecurityToken");
String ticket = temp[1];
ticket = ticket.substring(15, (ticket.length() - 7));
ticket = ticket.replaceAll("&", "&");
temp = data.split("BinarySecret");
String secret = temp[1];
secret = secret.substring(1, (secret.length() - 6));
// fill random iv
byte[] iv = new byte[8];
for (int i = 0; i < 8; i++) {
byte rand = (byte) Math.floor(Math.random() * 256);
iv[i] = rand;
}
// fill the begining of the struct
byte start[] = new byte[28];
// uStructHeaderSize = 28
start[0] = 0x1c;
start[1] = 0x00;
start[2] = 0x00;
start[3] = 0x00;
// uCryptMode = 1
start[4] = 0x01;
start[5] = 0x00;
start[6] = 0x00;
start[7] = 0x00;
// uCipherType = 0x6603
start[8] = 0x03;
start[9] = 0x66;
start[10] = 0x00;
start[11] = 0x00;
// uHashType = 0x8004
start[12] = 0x04;
start[13] = (byte) 0x80;
start[14] = 0x00;
start[15] = 0x00;
// uIVLen = 8
start[16] = 0x08;
start[17] = 0x00;
start[18] = 0x00;
start[19] = 0x00;
// uHashLen = 20
start[20] = 0x14;
start[21] = 0x00;
start[22] = 0x00;
start[23] = 0x00;
// uCipherLen = 72
start[24] = 0x48;
start[25] = 0x00;
start[26] = 0x00;
start[27] = 0x00;
// generate key's
byte key1[] = Base64Coder.decode(secret);
byte key2[] = derive_key(key1, "WS-SecureConversationSESSION KEY HASH".getBytes());
byte key3[] = derive_key(key1, "WS-SecureConversationSESSION KEY ENCRYPTION".getBytes());
// create hash
byte hash[] = HMAC(key2, nonce.getBytes());
// add 8 bytes to the nonce
byte nonceFillup[] = new byte[8];
for (int i = 0; i < 8; i++) {
nonceFillup[i] = 0x08;
}
// create des3 thingy
byte des[] = DES3(key3, byteCombine(nonce.getBytes(), nonceFillup), iv);
// fill struct
byte struct[] = byteCombine(byteCombine(byteCombine(start, iv), hash), des);
// return stuff
return ticket + " " + new String(Base64Coder.encode(struct));
}
/**
* 读取安全检验POST文件内容
*
* @param username
* @param password
* @param policy
* @return
*/
public static String loadConfigMap(String username, String password, String policy) {
// 数据初始化//配置文件读取
final String XML_NAME = "data/protocol/" + "RPS.xml";
final String USER_NAME = "JMUserName";
final String PASSWORD = "JMPassWord";
final String POLICY = "JMPolicy";
try {
StringBuffer buf2 = new StringBuffer();
String dataline;
InputStream setdata = new FileInputStream(new File(XML_NAME));
BufferedReader in = new BufferedReader(new InputStreamReader(setdata));
while ((dataline = in.readLine()) != null) {
buf2.append(dataline);
}
setdata.close();
in.close();
dataline = buf2.toString();
dataline = dataline.replaceAll(USER_NAME, username);
dataline = dataline.replaceAll(PASSWORD, password);
dataline = dataline.replaceAll(POLICY, policy);
return new String(dataline.getBytes("utf-8"));
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
return "";
}
private static byte[] derive_key(byte[] key, byte[] magic) {
byte hash1[] = HMAC(key, magic);
byte hash2[] = HMAC(key, byteCombine(hash1, magic));
byte hash3[] = HMAC(key, hash1);
byte hash4[] = HMAC(key, byteCombine(hash3, magic));
byte out[] = new byte[4];
out[0] = hash4[0];
out[1] = hash4[1];
out[2] = hash4[2];
out[3] = hash4[3];
return byteCombine(hash2, out);
}
private static byte[] HMAC(byte[] key, byte[] subject) {
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec sk = new SecretKeySpec(key, "HmacSHA1");
mac.init(sk);
return mac.doFinal(subject);
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
} catch (InvalidKeyException ex) {
ex.printStackTrace();
}
return null;
}
private static byte[] byteCombine(byte[] front, byte[] back) {
byte output[] = new byte[front.length + back.length];
for (int i = 0; i < front.length; i++) {
output[i] = front[i];
}
for (int i = 0; i < back.length; i++) {
output[i + front.length] = back[i];
}
return output;
}
private static byte[] DES3(byte[] key, byte[] subject, byte[] iv) {
try {
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
SecretKeySpec sk = new SecretKeySpec(key, "DESede");
IvParameterSpec sr = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, sk, sr);
return cipher.doFinal(subject);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -