I believe this is a pretty basic question, but I'm starting the studies in JavaScript and in RSA, so I'm a little bit lost. I just downloaded the library Cryptico, which gives me an easy to use RSA key gen/encryption/decryption. The public part of the generated RSA Key, can be extracted easily just using the command:
publicKeyString(RsaKey)
Which is:
my.publicKeyString = function(rsakey)
{
pubkey = my.b16to64(rsakey.n.toString(16));
return pubkey;
}
The rsakey.n is defined while generating the key in the function:
function RSAGenerate(B, E)
{
var rng = new SeededRandom();
var qs = B >> 1;
this.e = parseInt(E, 16);
var ee = new BigInteger(E, 16);
for (;;)
{
for (;;)
{
this.p = new BigInteger(B - qs, 1, rng);
if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break;
}
for (;;)
{
this.q = new BigInteger(qs, 1, rng);
if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break;
}
if (this.p.compareTo(this.q) <= 0)
{
var t = this.p;
this.p = this.q;
this.q = t;
}
var p1 = this.p.subtract(BigInteger.ONE);
var q1 = this.q.subtract(BigInteger.ONE);
var phi = p1.multiply(q1);
if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0)
{
this.n = this.p.multiply(this.q);
this.d = ee.modInverse(phi);
this.dmp1 = this.d.mod(p1);
this.dmq1 = this.d.mod(q1);
this.coeff = this.q.modInverse(this.p);
break;
}
}
}
But the private part of the key, I just can't understand how to extract, so I'll be able to save public/private key parts and available for later using.
Library Documentation:
https://github.com/wwwtyro/cryptico
RSA is defined in such a way that the values contained in a public key make up a subset of the values contained in the private key. So your private key is already rsakey. Other public key schemes work differently where public and private key values are completely distinct.
Furthermore rsakey.n doesn't fully define the public key. You need at least the public exponent e. It is often simply set to 65537, so this might be hardcoded if you never need to change the key or upgrade the scheme. It's the E in RSAGenerate. It is ignored in this case, because
A (seeded) random RSA key is generated with Tom Wu's RSA key generator with 3 as a hard-coded public exponent.
You can choose a similar encoding of the private key as the public key, but since it has to hold multiple values, I opted for JSON serialization:
(function(c){
var parametersBigint = ["n", "d", "p", "q", "dmp1", "dmq1", "coeff"];
c.privateKeyString = function(rsakey) {
var keyObj = {};
parametersBigint.forEach(function(parameter){
keyObj[parameter] = c.b16to64(rsakey[parameter].toString(16));
});
// e is 3 implicitly
return JSON.stringify(keyObj);
}
c.privateKeyFromString = function(string) {
var keyObj = JSON.parse(string);
var rsa = new RSAKey();
parametersBigint.forEach(function(parameter){
rsa[parameter] = parseBigInt(c.b64to16(keyObj[parameter].split("|")[0]), 16);
});
rsa.e = parseInt("03", 16);
return rsa
}
})(cryptico)
Related
I have the following code for decryption in java, I want that to be implemented in nodejs but the i found many tuto for my problem but they use a salt and that don't work when i try to remove the salt system.
My olds functions from java
public void readLastLogin(File lastLogin) {
try {
final Cipher ciph = this.openCipher(Cipher.DECRYPT_MODE);
final DataInputStream dis = new DataInputStream(new CipherInputStream(new FileInputStream(lastLogin), ciph));
String user = dis.readUTF();
String token = dis.readUTF();
dis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void saveLastLogin(File lastLogin, String user, String token) {
try {
final Cipher ciph = this.openCipher(Cipher.ENCRYPT_MODE);
final DataOutputStream dos = new DataOutputStream(new CipherOutputStream(new FileOutputStream(lastLogin), ciph));
dos.writeUTF(user);
dos.writeUTF(token);
dos.close();
} catch (final Exception e) {
e.printStackTrace();
}
}
private Cipher openCipher(final int mode) throws Exception {
final Random rnd = new Random(43287234L);
final byte[] data = new byte[8];
rnd.nextBytes(data);
final PBEParameterSpec spec = new PBEParameterSpec(data, 5);
final SecretKey key = SecretKeyFactory
.getInstance("PBEWithMD5AndDES")
.generateSecret(new PBEKeySpec("mysecretpassword".toCharArray()));
final Cipher ret = Cipher.getInstance("PBEWithMD5AndDES");
ret.init(mode, key, spec);
return ret;
}
I try this but not working
KDF(password, iterations) {
var key = new Buffer(password,'utf-8');
var i;
for (i = 0; i < iterations; i+=1) {
key = crypto.createHash("md5").update(key).digest();
}
return key;
}
getKeyIV(password, iterations) {
var key = this.KDF(password, iterations);
var keybuf = new Buffer(key,'binary').slice(0,8);
var ivbuf = new Buffer(key,'binary').slice(8,16);
return [ keybuf, ivbuf ];
}
decrypt(message) {
var kiv = this.getKeyIV('password' ,5);
var decipher = crypto.createDecipheriv('des-ede', kiv[0], kiv[1]);
var result = decipher.update(message, 'hex', 'utf-8');
return result + decipher.final('utf-8');
}
Edit: The salt generated at runtime of the Java code is hex encoded: 0x0C9D4AE41E8315FC
final byte[] data = new byte[8];
data[0] = 12;
data[1] = -99;
data[2] = 74;
data[3] = -28;
data[4] = 30;
data[5] = -125;
data[6] = 21;
data[7] = -4;
There are three issues in the code:
The Java code uses writeUTF(). This is based on modified UTF-8, with two additional bytes prepended to contain the data size. A NodeJS library for modified UTF-8 is mutf-8.
Instead of des-ede (3DES/2TDEA in ECB mode), des-cbc (DES in CBC mode) must be applied. If DES is not available in the used NodeJS version, it can be mimicked with 3DES/2TDEA in CBC mode, des-ede-cbc, where the 8 bytes key has to be concatenated with itself to a 16 bytes key, reducing 3DES to DES. This workaround has the disadvantage of a performance loss.
The Java code applies a static 8 byte salt because Random() is instantiated with a static seed. This salt can be determined at runtime to (hex encoded): 0x0C9D4AE41E8315FC.
pbewithmd5anddes-js is a port of PBEWithMD5AndDES to NodeJS, from which the KDF(), getKeyIV() and decrypt() methods can be used, but must be adapted taking into account the above points. In addition, the functionality of readUTF() (the counterpart of writeUTF()) must be implemented. One possible solution is:
var crypto = require('crypto');
const { MUtf8Decoder } = require("mutf-8");
var pbewithmd5anddes = {
KDF: function(password,salt,iterations) {
var pwd = Buffer.from(password,'utf-8');
var key = Buffer.concat([pwd, salt]);
var i;
for (i = 0; i < iterations; i+=1) {
key = crypto.createHash('md5').update(key).digest();
}
return key;
},
getKeyIV: function(password,salt,iterations) {
var key = this.KDF(password,salt,iterations);
var keybuf = Buffer.from(key,'binary').subarray(0,8);
var ivbuf = Buffer.from(key,'binary').subarray(8,16);
return [ keybuf, ivbuf ];
},
decrypt: function(payload,password,salt,iterations) {
var encryptedBuffer = Buffer.from(payload,'base64');
var kiv = this.getKeyIV(password,salt,iterations);
//var decipher = crypto.createDecipheriv('des-cbc', kiv[0], kiv[1]); // Fix 1: If supported, apply DES-CBC with key K
var decipher = crypto.createDecipheriv('des-ede-cbc', Buffer.concat([kiv[0], kiv[0]]), kiv[1]); // otherwise DES-EDE-CBC with key K|K
var decryptedBuf = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()])
var decrypted = this.readUTF(decryptedBuf) // Fix 2: apply writeUTF counterpart
return decrypted;
},
readUTF: function(decryptedBuf) {
var decoder = new MUtf8Decoder()
var decryptedData = []
var i = 0;
while (i < decryptedBuf.length){
var lengthObj = decryptedBuf.readInt16BE(i);
var bytesObj = decryptedBuf.subarray(i+2, i+2+lengthObj);
var strObj = decoder.decode(bytesObj)
decryptedData.push(strObj)
i += 2 + lengthObj;
}
return decryptedData;
}
};
Test:
On the Java side, the following is executed:
saveLastLogin(file, "This is the first plaintext with special characters like §, $ and €.", "This is the second plaintext with special characters like §, $ and €.");
The raw ciphertext written to file is Base64 encoded:
Ow8bdeNM0QpNFQaoDe7dhG3k9nWz/UZ6v3+wQVgrD5QvWR/4+sA+YvqtnQBsy35nQkwhwGRBv1h1eOa587NaFtnJUWVHsRsncLWZ05+dD2rYVpcZRA8s6P2iANK6yLr+GO/+UpZpSe0fA4fFqEK1nm3U7NXdyddfuOlZ3h/RiyxK5819LieUne4F8/TpMzT0RIWkxqagbVw=
This can be decrypted on the NodeJS side with:
var payload = 'Ow8bdeNM0QpNFQaoDe7dhG3k9nWz/UZ6v3+wQVgrD5QvWR/4+sA+YvqtnQBsy35nQkwhwGRBv1h1eOa587NaFtnJUWVHsRsncLWZ05+dD2rYVpcZRA8s6P2iANK6yLr+GO/+UpZpSe0fA4fFqEK1nm3U7NXdyddfuOlZ3h/RiyxK5819LieUne4F8/TpMzT0RIWkxqagbVw=';
var password = 'mysecretpassword';
var salt = Buffer.from('0C9D4AE41E8315FC', 'hex');
var iterations = 5;
var decrypted = pbewithmd5anddes.decrypt(payload,password,salt,iterations);
console.log(decrypted);
with the output:
[
'This is the first plaintext with special characters like §, $ and €.',
'This is the second plaintext with special characters like §, $ and €.'
]
Note that the code contains serious vulnerabilities:
PBEWithMD5AndDES uses a key derivation based on the broken MD5 digest (PBKDF1), and as encryption algorithm the deprecated DES (officially withdrawn almost 20 years ago).
Use of a static salt.
An iteration count of 5 is generally much too small.
Random() (unlike SecureRandom()) is not cryptographically strong. Also note that it is not a good idea to use a PRNG like Random() for deterministic key derivation, as the implementation may change, leading to different results even with the same seed.
Here is my code:
const crypto = require('crypto')
let enterJS = 'h';
let enterStr = null;
enterStr = encrypt(enterJS, 'des-ecb').toUpperCase();
console.log("===============>>>> ENTER STR : " + enterStr);
function encrypt(plaintext, algorithm) {
var keyStr = "imtestKey";
var key = new Buffer(keyStr);
var cipher = crypto.createCipher(algorithm, key);
cipher.setAutoPadding(true);
var ciph = cipher.update(plaintext, 'ascii');
var ciphf = cipher.final();
return ciph.toString('hex') + ciphf.toString('hex');
}
But the result I got is:
===============>>>> ENTER STR : 16CE7F2DEB9BB56D
which the right result I test on this web: http://tool.chacuo.net/cryptdes
des-mode:ecb
fill-mode:pkcs7padding
password:imtestKey
output:hex
The right result (the same with my java code) is
832e52ebd3fb9059
My node version is v8.9.0, how can I get the right result?
This is my java code:
import java.lang.StringBuilder;
import javax.crypto.Cipher;
import java.security.SecureRandom;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
public class Test {
public static void main(String[] args) {
String js = "h";
try {
byte[] bs = encrypt(js.getBytes(), "imtestKey".getBytes());
System.out.println(byte2hex(bs));
} catch(Exception ex) {
}
}
public static byte[] encrypt(byte[] src, byte[] key) throws Exception {
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return cipher.doFinal(src);
}
public static String byte2hex(byte[] b) {
StringBuilder sb = new StringBuilder();
String stmp = "";
for(int n = 0; b != null && n < b.length; ++n) {
stmp = Integer.toHexString(b[n] & 255);
if (stmp.length() == 1) {
sb.append("0").append(stmp);
} else {
sb.append(stmp);
}
}
return sb.toString().toUpperCase();
}
}
Security aspects aside (as has been pointed out, DES and ECB, as well as no key derivation is insecure), you are using a deprecated crypto.createCipher() function which derives a key from the provided password.
The implementation of crypto.createCipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same password always creates the same key. The low iteration count and non-cryptographically secure hash algorithm allow passwords to be tested very rapidly.
Use crypto.createCipheriv() instead, which uses the provided key as-is:
const crypto = require('crypto')
let enterJS = 'h';
let enterStr = null;
function encrypt(plaintext, algorithm) {
var keyStr = "imtestKey";
var key = Buffer.alloc(8, keyStr);
var cipher = crypto.createCipheriv(algorithm, key, Buffer.alloc(0));
cipher.setAutoPadding(true);
var ciph = cipher.update(Buffer.from(plaintext));
var ciphf = cipher.final();
return Buffer.concat([ciph, ciphf]).toString('hex');
}
enterStr = encrypt(enterJS, 'des-ecb').toUpperCase();
console.log("===============>>>> ENTER STR : " + enterStr);
The createCipheriv API will reject your 9-byte long key, because DES requires an 8-byte key. I made a workaround to take the first 8 bytes from the provided password as the key and now it's printing your desired result.
Output:
===============>>>> ENTER STR : 832E52EBD3FB9059
I'm use four arrays to generate difference test case, like below
var phone = ['phone1', 'phone2', 'phone3'];
var browsers = ['chrome', 'firefox'];
var location = ['1324','2434','4234','1234','3243'];
var network = ['3g', '4g', 'wifi'];
var isLogin = ['service worker', 'no service worker'];
How do I write code that will generate the test case (180 difference case). I try for loop and recursion. I just can't seem to figure out a perfect way to do it. note I'm using javascript. can only use array for loop, can't use object due to some reason.
Can anyone give me some inspiration ?
I tried some scenario in Java(Approach can be applicable in same way for Javascript) with recursion, In this case I use 3 arrays and for 2 of them I use recursion.
public class Test3 {
static String[] names = { "Ram", "Shyam", "Mohan", "Rohan", "Saket" };
static String[] citys = { "Bhopal", "Indore", "Ujjan", "Dewas", "Rewa" };
static String[] addresses = { "add1", "add2", "add3", "add4", "add5" };
static StringBuffer buffer = new StringBuffer();
public static void main(String... strings) {
for (String a : names) {
System.out.println(testData(a)+"\n");
buffer.setLength(0);
}
}
public static String testData(String name) {
return generateData(name, 0, -1);
}
public static String generateData(String combination, int countA, int countB) {
if ((countA == names.length - 1) && (countB == names.length - 1)) {
return buffer.toString();
}
if (countB == addresses.length - 1) {
countA = countA + 1;
countB = -1;
}
countB = countB + 1;
buffer.append(combination + citys[countA] + addresses[countB] + "\n");
return generateData(combination, countA, countB);
}
}
Hope this will help!!
I found this code in c#. Its a dummy question but I don't know anything about encryption. This code encrypt and decrypt but there is no password field where should I put. This is the code that I found which is compatible with the java-script code so I really want it to work at last. Thank you :
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
namespace Rextester
{
class Program
{
public static void Main(string[] args)
{
string s = "Please enter UserName";
var encry = EncryptStringAES(s);
var dec = DecryptStringAES(encry);
Console.WriteLine(encry);
Console.WriteLine(dec);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
public static string DecryptStringAES(string cipherText)
{
var keybytes = Encoding.UTF8.GetBytes("8080808080808080");
var iv = Encoding.UTF8.GetBytes("8080808080808080");
var encrypted = Convert.FromBase64String(cipherText);
var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
return string.Format(decriptedFromJavascript);
}
private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
{
throw new ArgumentNullException("cipherText");
}
if (key == null || key.Length <= 0)
{
throw new ArgumentNullException("key");
}
if (iv == null || iv.Length <= 0)
{
throw new ArgumentNullException("key");
}
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new RijndaelManaged())
{
//Settings
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
try
{
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
catch
{
plaintext = "keyError";
}
}
return plaintext;
}
public static string EncryptStringAES(string plainText)
{
var keybytes = Encoding.UTF8.GetBytes("8080808080808080");
var iv = Encoding.UTF8.GetBytes("8080808080808080");
var encryoFromJavascript = EncryptStringToBytes(plainText, keybytes, iv);
return Convert.ToBase64String(encryoFromJavascript);
}
private static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
{
throw new ArgumentNullException("plainText");
}
if (key == null || key.Length <= 0)
{
throw new ArgumentNullException("key");
}
if (iv == null || iv.Length <= 0)
{
throw new ArgumentNullException("key");
}
byte[] encrypted;
// Create a RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new RijndaelManaged())
{
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
}
}
The java-script I know where to put the password but in c# I don't know:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js "></script>
<script type="text/javascript">
function SubmitsEncry() {
debugger;
var txtUserName = "Please enter UserName";
var key = CryptoJS.enc.Utf8.parse('8080808080808080');
var iv = CryptoJS.enc.Utf8.parse('8080808080808080');
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(txtUserName),'1', key,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var decrypted = CryptoJS.AES.decrypt(encrypted,'1', key,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
alert(encrypted);
}
SubmitsEncry();
</script>
I'm not sure I fully understand the extent of your question, but if it is as simple as it appears to be, you could always Ctrl-F to find the key in the C# code. It's the line that starts with var keybytes = Encoding.UTF8.GetBytes("80...
However, the code that you have isn't going to do what you want. It is insecure and easily broken (since the key is literally in the code). Your lack of understanding of cryptography in general is also going to limit your ability to create the solution I think you are envisioning.
Some advice:
If you want to use a password, you need to understand that this is fundamentally different from a key. Use a KDF to derive a key from a password. PBKDF2 is good.
Don't use a fixed IV. If the IV remains the same then you compromise the encryption. It should be different every time you encrypt. It doesn't need to be secret at all, just different.
Use an authenticated mode if you can (GCM), otherwise use an HMAC to authenticate your ciphertext. If you don't do this, anyone can change the contents of the file (even if it is encrypted) and you won't know that this has happened.
I recommend you view the examples in this repository. There are examples for both C# and browser JavaScript.
I have used some client side javscript code to compress some user input using this javascript library.
In the backend code I have used the code samples from this post to decompress the data server side using C#.
The works perfectly.
Now I would like to be able to compress a string the same way the javascript does. When I compress the code using this sample I get an array of signed integers ranging from -128 to 128. Now I would like to use my backend code to do the same.
The LMZA properties from the javascript are a bit different than the default properties from the C# code but even if I change those to the same values I get different results from the two libraries.
At first the output values from the C# code are unsigned.
Secondly the number of characters returned are different.
The differences may be introduced by the properties of the decoders but I have no idea how to get the two libraries aligned.
My C# uses the LMZA SDK from 7zip
My C# code to decompress the javascript compressed data (comma separated array of signed integers):
public static void Decompress(Stream inStream, Stream outStream)
{
byte[] properties = new byte[5];
inStream.Read(properties, 0, 5);
SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
decoder.SetDecoderProperties(properties);
long outSize = 0;
for (int i = 0; i < 8; i++)
{
int v = inStream.ReadByte();
outSize |= ((long)(byte)v) << (8 * i);
}
long compressedSize = inStream.Length - inStream.Position;
decoder.Code(inStream, outStream, compressedSize, outSize, null);
}
public static string DecompressLzma(string inputstring)
{
if (!string.IsNullOrEmpty(inputstring))
{
byte[] myInts = Array.ConvertAll(inputstring.Split(','), s => (byte)int.Parse(s));
var stream = new MemoryStream(myInts);
var outputStream = new MemoryStream();
Decompress(stream, outputStream);
using (var reader = new StreamReader(outputStream))
{
outputStream.Position = 0;
string output = reader.ReadToEnd();
return output;
}
}
return "";
}
The code to compress the data is like this (number of bytes are diffrent and unsigned):
public static string CompressLzma(string inputstring)
{
if (!string.IsNullOrEmpty(inputstring))
{
var stream = new MemoryStream(Encoding.Unicode.GetBytes(inputstring ?? ""));
var outputStream = new MemoryStream();
Compress(stream, outputStream);
byte[] bytes = outputStream.ToArray();
}
return "";
}
public static void Compress(MemoryStream inStream, MemoryStream outStream)
{
CoderPropID[] propIDs;
object[] properties;
PrepareEncoder(out propIDs, out properties);
SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
encoder.SetCoderProperties(propIDs, properties);
encoder.WriteCoderProperties(outStream);
Int64 fileSize = inStream.Length;
for (int i = 0; i < 8; i++)
{
outStream.WriteByte((Byte)(fileSize >> (8 * i)));
}
encoder.Code(inStream, outStream, -1, -1, null);
}
public static void PrepareEncoder(out CoderPropID[] propIDs, out object[] properties)
{
bool eos = true;
Int32 dictionary = 1 << 16;
Int32 posStateBits = 2;
Int32 litContextBits = 3; // for normal files
// UInt32 litContextBits = 0; // for 32-bit data
Int32 litPosBits = 0;
// UInt32 litPosBits = 2; // for 32-bit data
Int32 algorithm = 2;
Int32 numFastBytes = 32;
string mf = "bt2";
propIDs = new CoderPropID[]
{
CoderPropID.DictionarySize,
CoderPropID.PosStateBits,
CoderPropID.LitContextBits,
CoderPropID.LitPosBits,
CoderPropID.Algorithm,
CoderPropID.NumFastBytes,
CoderPropID.MatchFinder,
CoderPropID.EndMarker
};
properties = new object[]
{
dictionary,
posStateBits,
litContextBits,
litPosBits,
algorithm,
numFastBytes,
mf,
eos
};
}
This code works to create the same string the javascript code would, the LMZA settings are included:
public static string CompressLzma(string inputstring)
{
if (!string.IsNullOrEmpty(inputstring))
{
var stream = new MemoryStream(Encoding.UTF8.GetBytes(inputstring ?? ""));
var outputStream = new MemoryStream();
Compress(stream, outputStream);
byte[] bytes = outputStream.ToArray();
var result = string.Join(",", Array.ConvertAll(bytes, v => signedInt((int)v)));
return result;
}
return "";
}
public static void PrepareEncoder(out CoderPropID[] propIDs, out object[] properties)
{
bool eos = true;
Int32 dictionary = 1 << 16;
Int32 posStateBits = 2;
Int32 litContextBits = 3; // for normal files
// UInt32 litContextBits = 0; // for 32-bit data
Int32 litPosBits = 0;
// UInt32 litPosBits = 2; // for 32-bit data
Int32 algorithm = 2;
Int32 numFastBytes = 64;
string mf = "bt4";
propIDs = new CoderPropID[]
{
CoderPropID.DictionarySize,
CoderPropID.PosStateBits,
CoderPropID.LitContextBits,
CoderPropID.LitPosBits,
CoderPropID.Algorithm,
CoderPropID.NumFastBytes,
CoderPropID.MatchFinder,
CoderPropID.EndMarker
};
properties = new object[]
{
dictionary,
posStateBits,
litContextBits,
litPosBits,
algorithm,
numFastBytes,
mf,
eos
};
}
private static int signedInt(int unsignedInt)
{
return unsignedInt >= 128 ? Math.Abs(128 - unsignedInt) - 128 : unsignedInt;
}
public static void Compress(MemoryStream inStream, MemoryStream outStream)
{
CoderPropID[] propIDs;
object[] properties;
PrepareEncoder(out propIDs, out properties);
SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
encoder.SetCoderProperties(propIDs, properties);
encoder.WriteCoderProperties(outStream);
Int64 fileSize = inStream.Length;
for (int i = 0; i < 8; i++)
{
outStream.WriteByte((Byte)(fileSize >> (8 * i)));
}
encoder.Code(inStream, outStream, -1, -1, null);
}