mirror of
https://github.com/skdatmonster/DecryptSourceProtection.git
synced 2025-03-08 22:19:02 -05:00
334 lines
14 KiB
HTML
334 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>RSLogix 5000 Source Protection Decryption</title>
|
|
<script src="aes.js"></script>
|
|
<script src="sha256.js"></script>
|
|
<script src="rc4.js"></script>
|
|
<script src="sha1.js"></script>
|
|
<script src="enc-utf16-min.js"></script>
|
|
<script>
|
|
"use strict";
|
|
var xpath = "//EncodedData|//*[@EncodedSourceKey]|//*[@SourceKey]";
|
|
|
|
var keymatl1 = CryptoJS.enc.Utf16LE.parse("Doug'sExportEncryption".slice(0, 11)); // Hi Doug
|
|
var keymatl2 = CryptoJS.enc.Hex.parse('5D002C0031006800610031004500580054002900240051005A003A005200370065006900390041004B0028005D005D00570034004800630031005C006A0040');
|
|
var keymatl3 = CryptoJS.enc.Hex.parse('5900530033003F0043004E0021004000420073004900740039006C0070002D003D0043004A003200300065004C004500760021005A0064004900530033002500680052006B00470070005700720079004F00590021006C00690021004C002F006E0038005F0023002A00760034002E0048007A00570048002D00700034007600');
|
|
var keymatl5 = CryptoJS.enc.Hex.parse('5300340079005400560049005A007A00240063003E005700380026005D0078002F003B004F00550065003F00660051006F007A003300620063005700260042007B0031005A00240068002B006F00460033005C004C003D0023004B005E00650055002500580032007300480048002B0055003D004D0063004E0037002900');
|
|
var keymatl6 = CryptoJS.enc.Hex.parse('277d3a6f747c647b457d587a502c7a5c4c793137617d24762e6a482a6f54433d553e746c6638655f504f682b68485d695e352c2a2d6f343e325a5d71262961');
|
|
var keymatl7 = CryptoJS.enc.Hex.parse('786d732a344075703d7d7556464065645769554c622e646b403b6e443c405372502e6c373f4a6b33326f5a457b697377552779286f483d4e53553a5e523f30');
|
|
var keymatl8 = CryptoJS.enc.Hex.parse('4f2a6b7a713d39495432234c3f7e7c3a775b2a4d674773577a717331436d345b2429456a6761433c5a282c323226724b654632267c392c7442276a2d2e723d');
|
|
|
|
function print(text, color) {
|
|
var output = document.getElementById('output');
|
|
var span = document.createElement('span');
|
|
span.style.color = color;
|
|
span.appendChild(document.createTextNode(text));
|
|
output.appendChild(span);
|
|
output.appendChild(document.createElement('br'));
|
|
}
|
|
|
|
function decrypt_8(b64text, format, embedded_iv) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
ciphertext = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(4));
|
|
var key = CryptoJS.SHA256(keymatl8);
|
|
var iv;
|
|
if (embedded_iv) {
|
|
iv = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(0, 32));
|
|
ciphertext = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(32));
|
|
} else {
|
|
iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
|
|
}
|
|
var options = {iv: iv, mode: CryptoJS.mode.CBC};
|
|
var decryptor = CryptoJS.algo.AES.createDecryptor(key, options);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsuccessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_7(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
ciphertext = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(4));
|
|
var key = CryptoJS.SHA256(keymatl7);
|
|
var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
|
|
var options = {iv: iv, mode: CryptoJS.mode.CBC};
|
|
var decryptor = CryptoJS.algo.AES.createDecryptor(key, options);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsuccessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_6(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
ciphertext = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(4));
|
|
var key = CryptoJS.SHA256(keymatl6);
|
|
var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
|
|
var options = {iv: iv, mode: CryptoJS.mode.CBC};
|
|
var decryptor = CryptoJS.algo.AES.createDecryptor(key, options);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsuccessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_5(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
ciphertext = CryptoJS.enc.Hex.parse(ciphertext.toString().slice(4));
|
|
var key = CryptoJS.SHA256(keymatl5);
|
|
var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
|
|
var options = {iv: iv, mode: CryptoJS.mode.CBC};
|
|
var decryptor = CryptoJS.algo.AES.createDecryptor(key, options);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsuccessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_3(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
var key = CryptoJS.SHA256(keymatl3);
|
|
var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
|
|
var options = {iv: iv, mode: CryptoJS.mode.CBC};
|
|
var decryptor = CryptoJS.algo.AES.createDecryptor(key, options);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsuccessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_2(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
var hashed = CryptoJS.SHA1(keymatl2);
|
|
var key = CryptoJS.enc.Hex.parse(hashed.toString(CryptoJS.enc.Hex).slice(0, 10) + '0000000000000000000000');
|
|
var decryptor = CryptoJS.algo.RC4.createDecryptor(key);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsucessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function decrypt_1(b64text, format) {
|
|
var ciphertext = CryptoJS.enc.Base64.parse(b64text);
|
|
var hashed = CryptoJS.SHA1(keymatl1);
|
|
var key = CryptoJS.enc.Hex.parse(hashed.toString(CryptoJS.enc.Hex).slice(0, 10) + '0000000000000000000000');
|
|
var decryptor = CryptoJS.algo.RC4.createDecryptor(key);
|
|
var part1 = decryptor.process(ciphertext);
|
|
var part2 = decryptor.finalize();
|
|
var plaintext = part1.toString(format) + part2.toString(format);
|
|
if (plaintext.length == 0 && ciphertext.words.length > 0) {
|
|
print('Decryption was unsucessful', 'red');
|
|
}
|
|
return plaintext;
|
|
}
|
|
|
|
function patchXML(data) {
|
|
try {
|
|
var encryptionConfig = 0;
|
|
var doc = new DOMParser().parseFromString(data, 'application/xml');
|
|
if (doc.getElementsByTagName('parsererror').length > 0) {
|
|
print('An XML parser error occurred, did you use a .L5X file?', 'red');
|
|
return '';
|
|
}
|
|
var flag = true;
|
|
while (flag)
|
|
{
|
|
var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
|
|
var element = result.singleNodeValue;
|
|
if (element == null) {
|
|
flag = false;
|
|
continue;
|
|
}
|
|
if (element.tagName == 'EncodedData') {
|
|
var temp = element.getAttribute('EncryptionConfig');
|
|
if (temp === null) {
|
|
encryptionConfig = 1;
|
|
} else if (temp == '2') {
|
|
encryptionConfig = 2;
|
|
} else if (temp == '3') {
|
|
encryptionConfig = 3;
|
|
} else if (temp == '5') {
|
|
encryptionConfig = 5;
|
|
} else if (temp == '6') {
|
|
encryptionConfig = 6;
|
|
} else if (temp == '7') {
|
|
encryptionConfig = 7;
|
|
} else if (temp == '8') {
|
|
encryptionConfig = 8;
|
|
} else {
|
|
print('Error: An unsupported EncryptionConfig value was found. (' + temp + ') Decryption of this file is not yet supported.', 'red');
|
|
return '';
|
|
}
|
|
var list = [];
|
|
for (var i = 0; i < element.childNodes.length; i++) {
|
|
var child = element.childNodes[i];
|
|
if (child.nodeType == Node.TEXT_NODE) {
|
|
list.push(child.nodeValue.replace(/\n/g, ''));
|
|
}
|
|
}
|
|
var decoded;
|
|
if (encryptionConfig == 1) {
|
|
decoded = decrypt_1(list.join(''), CryptoJS.enc.Utf16LE);
|
|
if (decoded.charCodeAt(decoded.length - 1) == 0) {
|
|
decoded = decoded.slice(0, decoded.length - 1);
|
|
}
|
|
} else if (encryptionConfig == 2) {
|
|
decoded = decrypt_2(list.join(''), CryptoJS.enc.Utf16LE);
|
|
if (decoded.charCodeAt(decoded.length - 1) == 0) {
|
|
decoded = decoded.slice(0, decoded.length - 1);
|
|
}
|
|
} else if (encryptionConfig == 3) {
|
|
decoded = decrypt_3(list.join(''), CryptoJS.enc.Utf16LE);
|
|
} else if (encryptionConfig == 5) {
|
|
decoded = decrypt_5(list.join(''), CryptoJS.enc.Utf16LE);
|
|
} else if (encryptionConfig == 6) {
|
|
decoded = decrypt_6(list.join(''), CryptoJS.enc.Utf16LE);
|
|
} else if (encryptionConfig == 7) {
|
|
decoded = decrypt_7(list.join(''), CryptoJS.enc.Utf16LE);
|
|
} else if (encryptionConfig == 8) {
|
|
decoded = decrypt_8(list.join(''), CryptoJS.enc.Utf8, true);
|
|
}
|
|
var subdoc = new DOMParser().parseFromString(decoded, 'application/xml');
|
|
if (subdoc.getElementsByTagName('parsererror').length > 0) {
|
|
print('An XML parser error occurred, decryption may have been unsuccessful', 'red');
|
|
return '';
|
|
}
|
|
for (var i = 0; i < subdoc.childNodes.length; i++) {
|
|
var imported = doc.importNode(subdoc.childNodes[i], true);
|
|
element.parentNode.insertBefore(imported, element);
|
|
}
|
|
element.parentNode.removeChild(element);
|
|
print('Unpacked encoded data', 'green');
|
|
} else if (element.hasAttribute('EncodedSourceKey')) {
|
|
var decoded;
|
|
if (encryptionConfig == 1) {
|
|
decoded = decrypt_1(element.getAttribute('EncodedSourceKey'), CryptoJS.enc.Latin1);
|
|
} else if (encryptionConfig == 2) {
|
|
decoded = decrypt_2(element.getAttribute('EncodedSourceKey'), CryptoJS.enc.Latin1);
|
|
} else if (encryptionConfig == 3) {
|
|
decoded = decrypt_3(element.getAttribute('EncodedSourceKey'), CryptoJS.enc.Latin1);
|
|
} else if (encryptionConfig == 5) {
|
|
decoded = decrypt_5(element.getAttribute('EncodedSourceKey'), CryptoJS.enc.Latin1);
|
|
}
|
|
element.removeAttribute('EncodedSourceKey');
|
|
if (element.hasAttribute('SourceProtectionType')) {
|
|
element.removeAttribute('SourceProtectionType');
|
|
}
|
|
if (element.hasAttribute('EditedDate')) {
|
|
var date = new Date(element.getAttribute('EditedDate'));
|
|
date.setMilliseconds(1 + date.getMilliseconds());
|
|
element.setAttribute('EditedDate', date.toISOString());
|
|
}
|
|
if (encryptionConfig == 6) {
|
|
print('Source key recovery is not supported for EncryptionConfig="6"', 'orange');
|
|
} else if (encryptionConfig == 7) {
|
|
print('Source key recovery is not supported for EncryptionConfig="7"', 'orange');
|
|
} else if (encryptionConfig == 8) {
|
|
print('Source key recovery is not supported for EncryptionConfig="8"', 'orange');
|
|
} else {
|
|
print('Found source key: "' + decoded + '"', 'green');
|
|
}
|
|
} else if (element.hasAttribute('SourceKey')) {
|
|
var sk = element.getAttribute('SourceKey');
|
|
element.removeAttribute('SourceKey');
|
|
if (element.hasAttribute('SourceProtectionType')) {
|
|
element.removeAttribute('SourceProtectionType');
|
|
}
|
|
if (element.hasAttribute('EditedDate')) {
|
|
var date = new Date(element.getAttribute('EditedDate'));
|
|
date.setMilliseconds(1 + date.getMilliseconds());
|
|
element.setAttribute('EditedDate', date.toISOString());
|
|
}
|
|
print('Found source key: "' + sk + '"', 'green');
|
|
}
|
|
}
|
|
return new XMLSerializer().serializeToString(doc);
|
|
} catch (e) {
|
|
print('Exception caught: ' + e, 'red');
|
|
console.log(e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
function handleDrop(event) {
|
|
if (event.dataTransfer.files.length == 1) {
|
|
var file = event.dataTransfer.files[0];
|
|
var fr = new FileReader();
|
|
fr.addEventListener('load', function(frevent) {
|
|
var textin = document.getElementById('textin');
|
|
var textout = document.getElementById('textout');
|
|
textin.value = frevent.target.result;
|
|
textout.value = patchXML(frevent.target.result);
|
|
textout.focus();
|
|
textout.select();
|
|
}, true);
|
|
fr.readAsText(file);
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function(event) {
|
|
document.getElementById('button').addEventListener('click', function(event) {
|
|
var textin = document.getElementById('textin');
|
|
var textout = document.getElementById('textout');
|
|
textout.value = patchXML(textin.value);
|
|
textout.focus();
|
|
textout.select();
|
|
}, true);
|
|
document.body.addEventListener('dragover', function(event) {
|
|
event.preventDefault();
|
|
}, true);
|
|
document.body.addEventListener('drop', function(event) {
|
|
event.preventDefault();
|
|
handleDrop(event);
|
|
}, true);
|
|
if (!document.evaluate) {
|
|
print('Your browser does not support XPath, please try again with a modern browser', 'red')
|
|
}
|
|
}, true);
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<form><table><tr>
|
|
<td>
|
|
<label for="textin">Input (with encrypted sections)</label>
|
|
<br />
|
|
<textarea id="textin" name="textin" rows="10" cols="40" placeholder="Paste the text of your exported XML here (starts with <?xml version=...)"></textarea>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<button id="button" type="button">Decrypt →</button>
|
|
</td>
|
|
<td>
|
|
<label for="textout">Output (decrypted)</label>
|
|
<br />
|
|
<textarea id="textout" name="textout" rows="10" cols="40" placeholder="Decrypted text will appear here"></textarea>
|
|
</td>
|
|
</tr></table></form>
|
|
<div id="output">
|
|
Drag a .L5X file onto this page, or open it in Notepad and paste its contents into the text box.
|
|
<br />
|
|
For more instructions, read the <a href="https://github.com/skdatmonster/DecryptSourceProtection/blob/master/README.md">README</a>.
|
|
<br />
|
|
</div>
|
|
</body>
|
|
</html>
|