diff --git a/test/shadowsocks/crypto/CryptoMethods/RC4.ts b/test/shadowsocks/crypto/CryptoMethods/RC4.ts new file mode 100644 index 0000000..93804af --- /dev/null +++ b/test/shadowsocks/crypto/CryptoMethods/RC4.ts @@ -0,0 +1,65 @@ +import * as crypto from "crypto"; +import CryptoTools from "../CryptoTools"; +import ICryptoKeyIV from "../ICryptoKeyIV"; +import ISSCryptoMethod from "../ISSCryptoMethod"; + +export default class RC4 implements ISSCryptoMethod { + + private static readonly keyLength: number = 16; + private static readonly ivLength: number = 0; + private static readonly cryptoName: string = "rc4"; + private cryptoKeyIV: ICryptoKeyIV; + + private isFirstEncryptData: boolean = true; + private isFirstDecryptData: boolean = true; + + private encryptProcess: crypto.Cipher = null; + private decryptProcess: crypto.Decipher = null; + + constructor(private password?: string) { + if (!password) { + return; + } + this.cryptoKeyIV = CryptoTools.generateKeyIVByPassword(this.password, RC4.keyLength, RC4.ivLength); + } + + public encryptData(data: Buffer): Buffer { + if (this.isFirstEncryptData) { + this.isFirstEncryptData = false; + this.cryptoKeyIV.iv = crypto.randomBytes(RC4.ivLength); + this.encryptProcess = crypto.createCipheriv("rc4", this.cryptoKeyIV.key , ""); + return Buffer.concat([this.cryptoKeyIV.iv, this.encryptProcess.update(data)]); + } + // tslint:disable-next-line:align + return this.encryptProcess.update(data); + } + + public decryptData(data: Buffer): Buffer { + if (this.isFirstDecryptData) { + this.isFirstDecryptData = false; + const decryptIV: Buffer = data.slice(0, RC4.ivLength); + this.decryptProcess = crypto.createDecipheriv("rc4", this.cryptoKeyIV.key, ""); + return this.decryptProcess.update(data.slice(RC4.ivLength)); + } + // tslint:disable-next-line:align + return this.decryptProcess.update(data); + } + + public encryptDataWithoutStream(data: Buffer) { + this.cryptoKeyIV.iv = crypto.randomBytes(RC4.ivLength); + // const rc4Process: Buffer = CryptoTools.generateRc4Md5KeyByKV(this.cryptoKeyIV); + const encryptProcess = crypto.createCipheriv("rc4", this.cryptoKeyIV.key , ""); + return Buffer.concat([this.cryptoKeyIV.iv, encryptProcess.update(data)]); + } + + public decryptDataWithoutStream(data: Buffer) { + const decryptIV: Buffer = data.slice(0, RC4.ivLength); + const decryptProcess = crypto.createDecipheriv("rc4", this.cryptoKeyIV.key, ""); + return decryptProcess.update(data.slice(RC4.ivLength)); + } + + public getCryptoName(): string { + return RC4.cryptoName; + } +} + diff --git a/test/shadowsocks/crypto/SSCrypto.ts b/test/shadowsocks/crypto/SSCrypto.ts index 99acd90..7a699ac 100644 --- a/test/shadowsocks/crypto/SSCrypto.ts +++ b/test/shadowsocks/crypto/SSCrypto.ts @@ -1,5 +1,6 @@ import ISSCryptoMethod from "./ISSCryptoMethod"; +import RC4 from "./CryptoMethods/RC4"; import RC4MD5 from "./CryptoMethods/RC4MD5"; import AES256CFB from "./CryptoMethods/AES256CFB"; import AES128GCM from "./CryptoMethods/AES128GCM"; @@ -8,6 +9,7 @@ import AES256GCM from "./CryptoMethods/AES256GCM"; const cryptoMethods: { [methodName: string]: any } = {}; +cryptoMethods[new RC4().getCryptoName().toLocaleLowerCase()] = RC4; cryptoMethods[new RC4MD5().getCryptoName().toLocaleLowerCase()] = RC4MD5; cryptoMethods[new AES256CFB().getCryptoName().toLocaleLowerCase()] = AES256CFB; @@ -15,6 +17,7 @@ cryptoMethods[new AES128GCM().getCryptoName().toLocaleLowerCase()] = AES128GCM; cryptoMethods[new AES192GCM().getCryptoName().toLocaleLowerCase()] = AES192GCM; cryptoMethods[new AES256GCM().getCryptoName().toLocaleLowerCase()] = AES256GCM; + export default class SSCrypto { public static getAllCryptoMethods(): Array {