Javascript中的TEA加密 [英] TEA Encryption in Javascript

查看:152
本文介绍了Javascript中的TEA加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Objective C TEA加密转换为Javascript,但在其中一个内部循环中,数字与Objective C版本不匹配



这是目标C版本

  #define TIMES 32 
@implementation NSData(NSData_extend)

//使用pwdKey加密NSData
- (NSData *)addTEA:(const unsigned int *)pwdkey
{
unsigned char * ch =(unsigned char *)[self bytes];
int n = 8-self.length%8;
char byte [self.length + n];
char cc = n;
for(int i = 0; i< n; i ++){
if(i == 0){
byte [i] = cc;
}
else {
byte [i] = 0;
}
}
for(int i = 0; i< self.length; i ++){
byte [n + i] = ch [i];
}

int delta = 0x9e3779b9;
int a = pwdkey [0];
int b = pwdkey [1];
int c = pwdkey [2];
int d = pwdkey [3];

unsigned char newbyte [self.length + n];
for(int offset = 0; offset< self.length + n; offset + = 8){
int y = [self ByteTounint:byte [offset + 3]] | [self ByteTounint:byte [offset + 2]]<< 8 | [self ByteTounint:byte [offset + 1]]<< 16 | [self ByteTounint:byte [offset + 0]]<< 24;
int z = [self ByteTounint:byte [offset + 7]] | [self ByteTounint:byte [offset + 6]]<< 8 | [self ByteTounint:byte [offset + 5]]<< 16 | [self ByteTounint:byte [offset + 4]]<< 24;

int sum = 0;
for(int i = 0; i< TIMES; i ++){
sum + = delta;
y + =((z << 4)+ a)^(z + sum)^((z>> 5)+ b);
z + =((y << 4)+ c)^(y + sum)^((y>> 5)+ d);
}
newbyte [offset + 7] = z& 0x000000ff;
newbyte [offset + 6] =(z& 0x0000ff00)>> 8;
newbyte [offset + 5] =(z& 0x00ff0000)>> 16;
newbyte [offset + 4] =(z& 0xff000000)>> 24;
newbyte [offset + 3] = y& 0x000000ff;
newbyte [offset + 2] =(y& 0x0000ff00)>> 8;
newbyte [offset + 1] =(y& 0x00ff0000)>> 16;
newbyte [offset + 0] =(y& 0xff000000)>> 24;
}

NSData * resultData = [NSData dataWithBytes:newbyte length:self.length + n];
返回resultData;
}

//使用pwdKey解密NSData
- (NSData *)subtractTEA:(const unsigned int *)pwdkey
{
unsigned char * byte =(unsigned char *)[self bytes];
int delta = 0x9e3779b9;
int a = pwdkey [0];
int b = pwdkey [1];
int c = pwdkey [2];
int d = pwdkey [3];
unsigned char newbyte [self.length];
for(int offset = 0; offset< self.length; offset + = 8){
int y = [self ByteTounint:byte [offset + 3]] | [self ByteTounint:byte [offset + 2]]<< 8 | [self ByteTounint:byte [offset + 1]]<< 16 | [self ByteTounint:byte [offset + 0]]<< 24;
int z = [self ByteTounint:byte [offset + 7]] | [self ByteTounint:byte [offset + 6]]<< 8 | [self ByteTounint:byte [offset + 5]]<< 16 | [self ByteTounint:byte [offset + 4]]<< 24;
int sum = 0;
if(TIMES == 32){
sum = 0xC6EF3720;
}
else if(TIMES == 16){
sum = 0xE3779B90;
}
else {
sum = delta * TIMES;
}

for(int i = 0; i< TIMES; i ++){
z - =((y << 4)+ c)^(y + sum) ^((y>>> 5)+ d);
y - =((z << 4)+ a)^(z + sum)^((z>> 5)+ b);
sum - = delta;
}
newbyte [offset + 7] = z& 0x000000ff;
newbyte [offset + 6] =(z& 0x0000ff00)>> 8;
newbyte [offset + 5] =(z& 0x00ff0000)>> 16;
newbyte [offset + 4] =(z& 0xff000000)>> 24;
newbyte [offset + 3] = y& 0x000000ff;
newbyte [offset + 2] =(y& 0x0000ff00)>> 8;
newbyte [offset + 1] =(y& 0x00ff0000)>> 16;
newbyte [offset + 0] =(y& 0xff000000)>> 24;
}
int n = newbyte [0];
unsigned char ch [self.length-n];
for(int i = 0; i< self.length-n; i ++){
ch [i] = newbyte [i + n];
}
NSData * resultData = [NSData dataWithBytes:ch length:self.length -n];
返回resultData;
}

- (int)ByteTounint:(int)byte
{
if(byte< 0){
return(byte + 256);
}
返回字节;
}

我的JavaScript版



< pre class =lang-js prettyprint-override> TEA.prototype.encrypt = function(src,pwdkey){
var TIMES = 32;
var n = 8 - (src.length%8);
var byte = Buffer.alloc(src.length + n);
var cc = n;

for(var i = 0; i< n; i ++){
if(i == 0){
byte [i] = cc;
}
else {
byte [i] = 0;
}
}

for(var j = 0; j< src.length; j ++){
byte.write(src [j],(n + J));

}
var delta = 0x9e3779b9;
var a = pwdkey.readInt32LE(0);
var b = pwdkey.readInt32LE(1);
var c = pwdkey.readInt32LE(2);
var d = pwdkey.readInt32LE(3);

var newbyte = Buffer.alloc(src.length + n);

for(var offset = 0; offset< src.length + n; offset + = 8){
var y = ByteTounint(byte [offset + 3])| ByteTounint(byte [offset + 2]<< 8)| ByteTounint(byte [offset + 1]<< 16)| ByteTounint(byte [offset + 0])<< 24;
var z = ByteTounint(byte [offset + 7])| ByteTounint(byte [offset + 6])<< 8 | ByteTounint(byte [offset + 5])<< 16 | ByteTounint(byte [offset + 4])<< 24;

var sum = 0;
for(var i = 0; i< TIMES; i ++)
{
sum + = delta;
sum>>> = 0;
y + =(((z << 4)+ a)^(z + sum)^((z>>>> 5)+ b))>>> 0;
z + =(((y << 4)+ c)^(y + sum)^((y>>>> 5)+ d))>>> 0;

}
newbyte.writeInt8((z& 0x000000ff),(offset + 7));
newbyte.writeInt8(((z& 0x0000ff00)>> 8),(offset + 6));
newbyte.writeInt8(((z& 0x00ff0000)>> 16),(offset + 5));
newbyte.writeInt8(((z& 0xff000000)>> 24),(offset + 4));

newbyte.writeInt8((y& 0x000000ff),(offset + 3));
newbyte.writeInt8(((y& 0x0000ff00)>> 8),(offset + 2));
newbyte.writeInt8(((y& 0x00ff0000)>> 16),(offset + 1));
newbyte.writeInt8(((y& 0xff000000)>> 24),(offset + 0));
}

返回newbyte

};

函数ByteTounint(byte){
if(byte< 0){
return(byte + 256);
}
返回字节;
}

JavaScript版本的使用

  var pwdkey = new Buffer(4523F10F214365873248738902EFCDAB,hex); 
var dene = tea.encrypt(params = {\method \:\waybill.querywaybill \,\requstParams\:{\memNo \: \ \,\ waybillNo\:\ 606447740110\}},pwdkey);

目标版本的用法和样本结果

  NSString * keyString = @4523F10F214365873248738902EFCDAB; 
NSData * keyData = [NSData dataWithHexString:keyString];
const unsigned char * src =(const unsigned char *)[key bytes];
NSString * str = @params = {\method \:\waybill.querywaybill \,\requstParams\:{\memNo \:\ \,\ waybillNo\:\ 606447740110\}};
NSData * data = [NSData dataWithBytes:str.UTF8String length:str.length];
NSData * result2 = [data addTEA:src];
NSLog(@%@,result2);
//打印167da396 9b183f2e d12ac3f5 5083a581 .....

我的版本开始给出中的错误值为(var i = 0; i< TIMES; i ++)循环。然后它在 newbyte.writeInt8 部分崩溃。

解决方案

最后,我使它工作。这是一个正常加密和解密任何文本大小的工作版本。

  function ByteTounint(byte){

if(byte< 0){
return(byte + 256);
}
返回字节;
}


TEA.prototype.decrypt = function(src,pwdkey){
var TIMES = 32;
var delta = 0x9e3779b9;

var a = pwdkey.readUInt32LE(0);
var b = pwdkey.readUInt32LE(4);
var c = pwdkey.readUInt32LE(8);
var d = pwdkey.readUInt32LE(12);

var newbyte = Buffer.alloc(src.length);

for(var offset = 0; offset< src.length; offset + = 8){
var y = ByteTounint(src [offset + 3])| ByteTounint(src [offset + 2])<< 8 | ByteTounint(src [offset + 1])<< 16 | ByteTounint(src [offset + 0])<< 24;
var z = ByteTounint(src [offset + 7])| ByteTounint(src [offset + 6])<< 8 | ByteTounint(src [offset + 5])<< 16 | ByteTounint(src [offset + 4])<< 24;


var sum = 0;
if(TIMES == 32){
sum = 0xC6EF3720;
}
else if(TIMES == 16){
sum = 0xE3779B90;
}
else {
sum = delta * TIMES;
}

for(var i = 0; i< TIMES; i ++){
z =(z - ((((y << 4)+ c)& ; 0xFFFFFFFF)^((y + sum)& 0xFFFFFFFF)^(((y>> 5)+ d)& 0xFFFFFFFF)))& 0xFFFFFFFF
y =(y - ((((z << 4)+ a)& 0xFFFFFFFF)^((z + sum)& 0xFFFFFFFF)^(((z>> 5)+ b )& 0xFFFFFFFF)))& 0xFFFFFFFF
sum =(sum-delta)& 0xFFFFFFFF的;
}

newbyte.writeInt32BE((y& 0xFFFFFFFF),offset);
newbyte.writeInt32BE((z& 0xFFFFFFFF),(offset + 4));
}

var n = newbyte [0];
var ch = Buffer.alloc(src.length - n);

for(var i = 0; i< src.length-n; i ++){
ch [i] = newbyte [i + n];
}

返回ch;
};

TEA.prototype.encrypt = function(src,pwdkey){
var TIMES = 32;
var n = 8 - (src.length%8);
var byte = Buffer.alloc(src.length + n);
var cc = n;

for(var i = 0; i< n; i ++){
if(i == 0){
byte [i] = cc;
}
else {
byte [i] = 0;
}
}


for(var j = 0; j< src.length; j ++){
byte.write(src [j ],第(n + j)的);

}
var delta = 0x9e3779b9;
var a = pwdkey.readUInt32LE(0);
var b = pwdkey.readUInt32LE(4);
var c = pwdkey.readUInt32LE(8);
var d = pwdkey.readUInt32LE(12);

var newbyte = Buffer.alloc(src.length + n);

for(var offset = 0; offset< src.length + n; offset + = 8){

var y = ByteTounint(byte [offset + 3]) | ByteTounint(byte [offset + 2])<< 8 | ByteTounint(byte [offset + 1])<< 16 | ByteTounint(byte [offset + 0])<< 24;
var z = ByteTounint(byte [offset + 7])| ByteTounint(byte [offset + 6])<< 8 | ByteTounint(byte [offset + 5])<< 16 | ByteTounint(byte [offset + 4])<< 24;

var sum = 0;

for(var i = 0; i< TIMES; i ++)
{
sum =(sum + delta)& 0xFFFFFFFF的;
y =(y +((((z << 4)+ a)& 0xFFFFFFFF)^((z + sum)& 0xFFFFFFFF)^(((z>> 5)+ b) & 0xFFFFFFFF)))& 0xFFFFFFFF的;
z =(z +((((y << 4)+ c)& 0xFFFFFFFF)^((y + sum)& 0xFFFFFFFF)^(((y>> 5)+ d) & 0xFFFFFFFF)))& 0xFFFFFFFF
}

newbyte.writeInt32BE((y& 0xFFFFFFFF),offset);
newbyte.writeInt32BE((z& 0xFFFFFFFF),(offset + 4));
}

返回newbyte

};

```


I am trying to convert Objective C TEA encryption to Javascript but inside one of the inner loops, numbers doesn't match against Objective C version

Here is the Objective C version

#define TIMES 32
@implementation NSData (NSData_extend)

// Encrypt NSData with pwdKey
-(NSData*)addTEA:(const unsigned int *)pwdkey
{
    unsigned char * ch = (unsigned char*)[self bytes];
    int n = 8-self.length%8;
    char byte[self.length+n];
    char cc = n;
    for (int i=0; i<n; i++) {
        if (i==0) {
            byte[i] = cc;
        }
        else{
            byte[i] = 0;
        }
    }
    for (int i=0; i<self.length; i++) {
        byte[n+i] = ch[i];
    }

    int delta = 0x9e3779b9;
    int a     = pwdkey[0];
    int b     = pwdkey[1];
    int c     = pwdkey[2];
    int d     = pwdkey[3];

    unsigned char newbyte[self.length+n];
    for (int offset=0; offset<self.length+n; offset += 8) {
        int y = [self ByteTounint:byte[offset+3]] | [self ByteTounint:byte[offset+2]]<<8 | [self ByteTounint:byte[offset+1]]<<16 | [self ByteTounint:byte[offset+0]]<<24;
        int z = [self ByteTounint:byte[offset+7]] | [self ByteTounint:byte[offset+6]]<<8 | [self ByteTounint:byte[offset+5]]<<16 | [self ByteTounint:byte[offset+4]]<<24;

        int sum = 0;
        for (int i=0; i<TIMES; i++) {
            sum += delta;
            y += ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b);
            z += ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d);
        }
        newbyte[offset+7] = z & 0x000000ff;
        newbyte[offset+6] = (z & 0x0000ff00) >> 8;
        newbyte[offset+5] = (z & 0x00ff0000) >> 16;
        newbyte[offset+4] = (z & 0xff000000) >> 24;
        newbyte[offset+3] = y & 0x000000ff;
        newbyte[offset+2] = (y & 0x0000ff00) >> 8;
        newbyte[offset+1] = (y & 0x00ff0000) >> 16;
        newbyte[offset+0] = (y & 0xff000000) >> 24;
    }

    NSData * resultData = [NSData dataWithBytes:newbyte length:self.length+n];
    return resultData;
}

// Decrypt NSData with pwdKey
-(NSData*)subtractTEA:(const unsigned int *)pwdkey
{
    unsigned char * byte = (unsigned char*)[self bytes];
    int delta = 0x9e3779b9;
    int a     = pwdkey[0];
    int b     = pwdkey[1];
    int c     = pwdkey[2];
    int d     = pwdkey[3];
    unsigned char newbyte[self.length];
    for (int offset=0; offset<self.length; offset += 8) {
        int y = [self ByteTounint:byte[offset+3]] | [self ByteTounint:byte[offset+2]]<<8 | [self ByteTounint:byte[offset+1]]<<16 | [self ByteTounint:byte[offset+0]]<<24;
        int z = [self ByteTounint:byte[offset+7]] | [self ByteTounint:byte[offset+6]]<<8 | [self ByteTounint:byte[offset+5]]<<16 | [self ByteTounint:byte[offset+4]]<<24;
        int sum = 0;
        if (TIMES == 32) {
            sum = 0xC6EF3720;
        }
        else if (TIMES == 16){
            sum = 0xE3779B90;
        }
        else{
            sum = delta * TIMES;
        }

        for (int i=0; i<TIMES; i++) {
            z   -= ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d);
            y   -= ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b);
            sum -= delta;
        }
        newbyte[offset+7] = z & 0x000000ff;
        newbyte[offset+6] = (z & 0x0000ff00) >> 8;
        newbyte[offset+5] = (z & 0x00ff0000) >> 16;
        newbyte[offset+4] = (z & 0xff000000) >> 24;
        newbyte[offset+3] = y & 0x000000ff;
        newbyte[offset+2] = (y & 0x0000ff00) >> 8;
        newbyte[offset+1] = (y & 0x00ff0000) >> 16;
        newbyte[offset+0] = (y & 0xff000000) >> 24;
    }
    int n = newbyte[0];
    unsigned char ch[self.length-n];
    for (int i=0; i<self.length-n; i++) {
        ch[i] = newbyte[i+n];
    }
    NSData * resultData = [NSData dataWithBytes:ch length:self.length-n];
    return resultData;
}

- (int)ByteTounint:(int)byte
{
    if (byte<0) {
        return (byte+256);
    }
    return byte;
}

My JavaScript version

TEA.prototype.encrypt = function(src,pwdkey) {
    var TIMES = 32;
    var n = 8 - (src.length % 8);
    var byte = Buffer.alloc(src.length + n);
    var cc = n;

    for (var i = 0; i < n; i++) {
        if (i == 0) {
            byte[i] = cc;
        }
        else {
            byte[i] = 0;
        }
    }

    for (var j = 0; j < src.length; j++) {
        byte.write( src[j],(n+j));

    }
    var delta = 0x9e3779b9;
    var a = pwdkey.readInt32LE(0);
    var b = pwdkey.readInt32LE(1);
    var c = pwdkey.readInt32LE(2);
    var d = pwdkey.readInt32LE(3);

    var newbyte = Buffer.alloc(src.length + n);

    for (var offset = 0; offset < src.length + n; offset += 8) {
        var y = ByteTounint(byte[offset + 3]) | ByteTounint(byte[offset + 2] << 8) | ByteTounint(byte[offset + 1] << 16) | ByteTounint(byte[offset + 0]) << 24;
        var z = ByteTounint(byte[offset + 7]) | ByteTounint(byte[offset + 6]) << 8 | ByteTounint(byte[offset + 5]) << 16 | ByteTounint(byte[offset + 4]) << 24;

        var sum = 0;
        for(var i=0;i<TIMES;i++)
        {
            sum += delta;
            sum >>>= 0;
            y += (((z<<4)+a) ^ (z+sum) ^ ((z>>>5)+b)) >>> 0;
            z += (((y<<4)+c) ^ (y+sum) ^ ((y>>>5)+d)) >>> 0;

        }
        newbyte.writeInt8((z & 0x000000ff),(offset + 7));
        newbyte.writeInt8(((z & 0x0000ff00) >> 8),(offset + 6));
        newbyte.writeInt8(((z & 0x00ff0000) >> 16),(offset + 5));
        newbyte.writeInt8(((z & 0xff000000) >> 24),(offset + 4));

        newbyte.writeInt8((y & 0x000000ff),(offset + 3));
        newbyte.writeInt8(((y & 0x0000ff00) >> 8),(offset + 2));
        newbyte.writeInt8(((y & 0x00ff0000) >> 16),(offset + 1));
        newbyte.writeInt8(((y & 0xff000000) >> 24),(offset + 0));
    }

    return newbyte

};

function ByteTounint(byte) {
    if (byte<0) {
        return (byte+256);
    }
    return byte;
}

Usage for JavaScript Version

var pwdkey = new Buffer("4523F10F214365873248738902EFCDAB","hex");
var dene = tea.encrypt("params={\"method\":\"waybill.querywaybill\",\"requstParams\":{\"memNo\":\"\",\"waybillNo\":\"606447740110\"}}",pwdkey);

Usage and Sample Result from Objective version

NSString *keyString = @"4523F10F214365873248738902EFCDAB";
NSData *keyData = [NSData dataWithHexString:keyString];
const unsigned char *src = (const unsigned char *)[key bytes];
NSString *str = @"params={\"method\":\"waybill.querywaybill\",\"requstParams\":{\"memNo\":\"\",\"waybillNo\":\"606447740110\"}}";
NSData *data = [NSData dataWithBytes:str.UTF8String length:str.length];
NSData * result2 = [data addTEA:src];
NSLog(@"%@",result2);
// prints 167da396 9b183f2e d12ac3f5 5083a581.....

My version starts to give wrong values inside for(var i=0;i<TIMES;i++) loop. Then it crashes during newbyte.writeInt8 part.

解决方案

Finally, I made it work. Here is a working version which correctly encrypts and decrypts any size of text.

function ByteTounint(byte) {

    if (byte<0) {
        return (byte+256);
    }
    return byte;
}


TEA.prototype.decrypt = function(src,pwdkey) {
    var TIMES = 32;
    var delta = 0x9e3779b9;

    var a = pwdkey.readUInt32LE(0);
    var b = pwdkey.readUInt32LE(4);
    var c = pwdkey.readUInt32LE(8);
    var d = pwdkey.readUInt32LE(12);

    var newbyte = Buffer.alloc(src.length);

    for (var offset=0; offset<src.length; offset += 8) {
        var y = ByteTounint(src[offset + 3]) | ByteTounint(src[offset + 2]) << 8 | ByteTounint(src[offset + 1]) << 16 | ByteTounint(src[offset + 0]) << 24;
        var z = ByteTounint(src[offset + 7]) | ByteTounint(src[offset + 6]) << 8 | ByteTounint(src[offset + 5]) << 16 | ByteTounint(src[offset + 4]) << 24;


        var sum = 0;
        if (TIMES == 32) {
            sum = 0xC6EF3720;
        }
        else if (TIMES == 16) {
            sum = 0xE3779B90;
        }
        else {
            sum = delta * TIMES;
        }

        for (var i = 0; i < TIMES; i++) {
            z = (z - (( ( (y<<4) + c) & 0xFFFFFFFF) ^ (  (y + sum) & 0xFFFFFFFF ) ^ ( ((y >> 5) + d ) & 0xFFFFFFFF))) & 0xFFFFFFFF
            y = (y - (( ( (z<<4) + a) & 0xFFFFFFFF) ^ (  (z + sum) & 0xFFFFFFFF ) ^ ( ((z >> 5) + b ) & 0xFFFFFFFF))) & 0xFFFFFFFF
            sum = (sum - delta) & 0xFFFFFFFF;
        }

        newbyte.writeInt32BE((y & 0xFFFFFFFF),offset);
        newbyte.writeInt32BE((z & 0xFFFFFFFF),(offset+4));
    }

    var n = newbyte[0];
    var ch = Buffer.alloc(src.length - n);

    for (var i=0; i<src.length-n; i++) {
        ch[i] = newbyte[i+n];
    }

    return ch;
};

TEA.prototype.encrypt = function(src,pwdkey) {
    var TIMES = 32;
    var n = 8 - (src.length % 8);
    var byte = Buffer.alloc(src.length + n);
    var cc = n;

    for (var i = 0; i < n; i++) {
        if (i == 0) {
            byte[i] = cc;
        }
        else {
            byte[i] = 0;
        }
    }


    for (var j = 0; j < src.length; j++) {
        byte.write( src[j],(n+j));

    }
    var delta = 0x9e3779b9; 
    var a = pwdkey.readUInt32LE(0);
    var b = pwdkey.readUInt32LE(4);
    var c = pwdkey.readUInt32LE(8);
    var d = pwdkey.readUInt32LE(12);

    var newbyte = Buffer.alloc(src.length + n);

    for (var offset = 0; offset < src.length + n; offset += 8) {

        var y = ByteTounint(byte[offset + 3]) | ByteTounint(byte[offset + 2]) << 8 | ByteTounint(byte[offset + 1]) << 16 | ByteTounint(byte[offset + 0]) << 24;
        var z = ByteTounint(byte[offset + 7]) | ByteTounint(byte[offset + 6]) << 8 | ByteTounint(byte[offset + 5]) << 16 | ByteTounint(byte[offset + 4]) << 24;

        var sum = 0;

        for(var i=0;i<TIMES;i++)
        {
            sum = (sum + delta) & 0xFFFFFFFF;
            y = (y + (( ( (z<<4) + a) & 0xFFFFFFFF) ^ (  (z + sum) & 0xFFFFFFFF ) ^ ( ((z >> 5) + b ) & 0xFFFFFFFF))) & 0xFFFFFFFF;
            z = (z + (( ( (y<<4) + c) & 0xFFFFFFFF) ^ (  (y + sum) & 0xFFFFFFFF ) ^ ( ((y >> 5) + d ) & 0xFFFFFFFF))) & 0xFFFFFFFF
        }

        newbyte.writeInt32BE((y & 0xFFFFFFFF),offset);
        newbyte.writeInt32BE((z & 0xFFFFFFFF),(offset+4));
    }

    return newbyte

};

```

这篇关于Javascript中的TEA加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆