Skip to content

Commit

Permalink
v3.3.0
Browse files Browse the repository at this point in the history
- unified the hash round return value with sha512 streamlining the hashing algorithms time to compute (on my device the max time dropped from 1500ms to 1050ms while the min time climbed from 350ms to 700ms)
- Now uses a regex function to detect emojis (thx to its creators) which means that the output is universally accepted, instead of an invisible divider symbol that can be removed due to text processing of different applications
- Uses a different approach for detecting encoded messages; now emoji-only messages are considered encoded
- Preperation of language support for parts yet to translated
  • Loading branch information
mqxym committed Nov 7, 2024
1 parent 947bdf7 commit 82e37a4
Showing 5 changed files with 181 additions and 44 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# EmojiCrypt Version 3.2.0 🌈
# EmojiCrypt Version 3.3.0 🌈

Your convenient and secure text encryption, where emojis are all that matters.
This repo is hosted here:
@@ -50,7 +50,7 @@ The idea is to implement a protocol where only you and the receiver knows what t
3. The hash before that
4. A custom, fixed salt that differs in each of the 16 switch cases
- Custom Hash Loop Lengths: As of version 1.1.0, different encryption algorithms have varying hash loop lengths and intermediate salt integers. Therefore, each of the three encryption algorithms uses a custom, deterministically derived key: 256-bit for AES and 4096-byte for XOR (as of version 3.0.0)
- *On modern devices, the hashing time can range from a minimum of 400 to a maximum of 1500 miliseconds and it is heavily dependent of the random salt*
- *On modern devices, the hashing time can range from a minimum of ~700 to a maximum of ~1000 miliseconds and it is dependent of the random salt resulting in more or less hash rounds and a different distribution in more computationally intensive hash functions (SHA-384,SHA-512)*
- Additional obfuscation: As of version 3.1.0, the binary-to-emoji algorithm employs a unique emoji sorting order derived from the input key.

## Includes ⤴️
10 changes: 5 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
@@ -224,12 +224,12 @@
<hr><hr>

<!-- Private Conversion Algorithm -->
<a class="btn btn-secondary bg-secondary btn-block text-light mb-3" data-toggle="collapse" data-target="#privateAlgorithmSection" aria-expanded="true" aria-controls="privateAlgorithmSection">💎 Private Algorithm</a>
<a class="btn btn-secondary bg-secondary btn-block text-light mb-3" data-toggle="collapse" data-target="#privateAlgorithmSection" aria-expanded="true" aria-controls="privateAlgorithmSection" id="showPrivateAlgorithmButton">💎 Private Algorithm</a>
<div id="privateAlgorithmSection" class="collapse">
<div class="card">
<div class="card-body">
<button id="generatePrivateConversionButton" type="button" class="btn btn-secondary bg-dark btn-block mb-2">🔮 Generate (new) private algorithm</button>
Your link to the private conversion algorithm: <br>
<span id="privateLinkText">Your link to the private conversion algorithm: </span> <br>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">🧬</span>
@@ -243,15 +243,15 @@
</div>

<div class="card-footer">
<i>
<i id="privateAlgorithmDisclaimer">
Using a private algorithm is just another layer of obfuscation, but can be cracked pretty easily.
<br>
Especially, when using the same algorithm more than once.
</i>
</div>
</div>
</div>
<i class="text-muted"> You can use a private algorithm with a unique key to obfuscate your messages.</i>
<i class="text-muted" id="privateAlgorithmFooter"> You can use a private algorithm with a unique key to obfuscate your messages.</i>
</div>
<!-- About Section -->
<div class="p-3 main-content info-section" id="aboutSection">
@@ -670,7 +670,7 @@ <h5 class="mb-0">

<footer class="bg-light text-left p-2">
<div class="mb-2">
<small class="text-muted">
<small id="siteFooter" class="text-muted">
Powered by <a class="text-muted" target="_blank" href="https://github.com/mqxym/EmojiCrypt"><u>EmojiCrypt</u></a> version <span id="versionFooter">3.1.0</span> built by <a class="text-muted" target="_blank" href="https://maxim.omg.lol"><u>@mqxym</u></a>
<br>
Legacy versions:
104 changes: 75 additions & 29 deletions js/emo.js
Original file line number Diff line number Diff line change
@@ -3,9 +3,19 @@
* @returns {string} The current version.
*/
function getVersion() {
return "3.2.0";
return "3.3.0";
}

/*
Hash count analysis
let s1 = 0;
let s2 = 0;
let s3 = 0;
let s5 = 0;
*/

/**
* Calculates a security level based on the SHA-256 hash of the password.
* @param {string} pass - The password input.
@@ -61,72 +71,91 @@ async function returnHash(seed) {
nibbles.push(byte & 0xF);
}

const caseSalts = [
encodeUTF8("SF39"),
encodeUTF8("DS44"),
encodeUTF8("XL55"),
encodeUTF8("NC01"),
encodeUTF8("LU50"),
encodeUTF8("GL12"),
encodeUTF8("GG31"),
encodeUTF8("HL11"),
encodeUTF8("XF91"),
encodeUTF8("BM15"),
encodeUTF8("TT85"),
encodeUTF8("RF19"),
encodeUTF8("MS25"),
encodeUTF8("0X80"),
encodeUTF8("MX55"),
encodeUTF8("WT66"),
];

for (const nibble of nibbles) {
let hashInput;

switch (nibble) {
case 0:
hashInput = concatUint8Arrays(key, encodeUTF8("SF39"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[0], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-384');
break;
case 1:
hashInput = concatUint8Arrays(key, encodeUTF8("DS44"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[1], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-384');
break;
case 2:
hashInput = concatUint8Arrays(key, encodeUTF8("XL55"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[2], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-384');
break;
case 3:
hashInput = concatUint8Arrays(key, encodeUTF8("NC01"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[3], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-384');
break;
case 4:
hashInput = concatUint8Arrays(key, encodeUTF8("LU50"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[4], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-512');
break;
case 5:
hashInput = concatUint8Arrays(key, encodeUTF8("GL12"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[5], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-512');
break;
case 6:
hashInput = concatUint8Arrays(key, encodeUTF8("GG31"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[6], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-512');
break;
case 7:
hashInput = concatUint8Arrays(key, encodeUTF8("HL11"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[7], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-512');
break;
case 8:
hashInput = concatUint8Arrays(key, encodeUTF8("XF91"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[8], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-256');
break;
case 9:
hashInput = concatUint8Arrays(key, encodeUTF8("BM15"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[9], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-256');
break;
case 10:
hashInput = concatUint8Arrays(key, encodeUTF8("TT85"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[10], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-256');
break;
case 11:
hashInput = concatUint8Arrays(key, encodeUTF8("RF19"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[11], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-1');
break;
case 12:
hashInput = concatUint8Arrays(key, encodeUTF8("MS25"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[12], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-1');
break;
case 13:
hashInput = concatUint8Arrays(key, encodeUTF8("0X80"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[13], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-1');
break;
case 14:
hashInput = concatUint8Arrays(key, encodeUTF8("MX55"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[14], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-1');
break;
case 15:
hashInput = concatUint8Arrays(key, encodeUTF8("WT66"), pastHashes[0], pastHashes[1]);
hashInput = concatUint8Arrays(key, caseSalts[15], pastHashes[0], pastHashes[1]);
key = await hashData(hashInput, 'SHA-256');
break;
}
@@ -136,7 +165,10 @@ async function returnHash(seed) {
pastHashes.shift();
}

return key;
const finalHashInput = concatUint8Arrays(...pastHashes);
const finalHash = await hashData(finalHashInput, 'SHA-512');

return finalHash;
}

/**
@@ -188,7 +220,7 @@ async function getCryptoKeys(keyInput, inputSalt = null) {
const securityLevelKeyBased = await getSecLevel(keyInput);
const securityLevelSaltBased = customSalt[0];
const securityLevelCombined = Math.floor((securityLevelKeyBased + securityLevelSaltBased) / 2);
const securityLevel = 383 + securityLevelCombined - 25;
const securityLevel = 383 + securityLevelCombined - 121;

// Step 4: Iterate hashPass based on security level
for (let i = 0; i < securityLevel; i++) {
@@ -244,6 +276,16 @@ async function getCryptoKeys(keyInput, inputSalt = null) {

console.timeEnd("keyHash");

/*
Hash count analysis
console.log(s1, s2, s3, s5, s1+s2+s3+s5)
s1 = 0;
s2 = 0;
s3 = 0;
s5 = 0;
*/

return { aesKey1, aesKey2, xorKey, customSalt };
}

@@ -279,7 +321,7 @@ async function encrypt(message, keyInput) {
// Step 6: Convert Encrypted Data to Emojis
const encryptedEmoji = mapBytesToSymbols(finalOutput, emojiArrayPermutation);

return encryptedEmoji.join("​");
return encryptedEmoji.join('');
}

/**
@@ -295,7 +337,9 @@ async function decrypt(message, keyInput) {
const standardEmojiArray = getEmojiArray();
const emojiArrayPermutation = await generateSecurePermutationFromString(keyInput, standardEmojiArray);

const decodedBytes = mapSymbolsToBytes(message.split("​"), emojiArrayPermutation);
const emojiArray = extractEmojis(message);

const decodedBytes = mapSymbolsToBytes(emojiArray, emojiArrayPermutation);

// Step 0.5: Split between salt and encrypted bytes and get the CryptoKeys using the salt
const customSalt = decodedBytes.slice(0,6);
@@ -323,20 +367,20 @@ async function decrypt(message, keyInput) {
/**
* Encodes a message into emojis without encryption.
* @param {string} message - The message to encode.
* @param {Array<string>} customEmojiArray - An custom order of the emoji Array generated by the private algorithm
* @param {Array<string>} customEmojiArray - A custom order of the emoji Array generated by the private algorithm
* @returns {string} The encoded message represented as emojis.
*/
function encode(message, customEmojiArray = null) {
const bytes = new TextEncoder().encode(message);
const emojis = customEmojiArray || getEmojiArray();
const encodedEmoji = mapBytesToSymbols(bytes, emojis);
return encodedEmoji.join("​");
return encodedEmoji.join('');
}

/**
* Decodes a message from emojis without decryption.
* @param {string} message - The message represented as emojis.
* @param {Array<string>} customEmojiArray - An custom order of the emoji Array generated by the private algorithm
* @param {Array<string>} customEmojiArray - A custom order of the emoji Array generated by the private algorithm
* @returns {string} The decoded message.
*/
function decode(message, customEmojiArray = null) {
@@ -345,7 +389,9 @@ function decode(message, customEmojiArray = null) {
const emojis = customEmojiArray || getEmojiArray();
try {
// Split into array and map emojis to bytes
bytes = mapSymbolsToBytes(message.split("​"), emojis);
const emojiArray = extractEmojis(message);

bytes = mapSymbolsToBytes(emojiArray, emojis);
decoded = new TextDecoder().decode(Uint8Array.from(bytes));
} catch (err) {
return "";
@@ -383,14 +429,14 @@ async function generateRandomKey() {
* @returns {string|boolean} Returns 'emoji' if it's an encoded emoji string, otherwise false.
*/
function checkInputString(inputString) {
const counts = countEmojisAndNonEmojis(inputString);

if (inputString === "") {
console.log("Input is empty");
return false;
}

// Count the number of zero-width spaces (used as separators)
if ((inputString.split('​').length - 1) > 2) {
console.log("Input is Encoded Emoji");
// at least 3 emojis and emoji only should count as encoded
if (counts.matches > 2 && counts.notMatches == 0) {
return "emoji";
}
return false;
16 changes: 8 additions & 8 deletions js/lang.js
Original file line number Diff line number Diff line change
@@ -355,7 +355,7 @@ function getTranslation(key, langIndex) {
// Messages during conversion
"btnEncodeWorkingConvert": [
"⚙️ Encoding...",
"⚙️ Kodieren...",
"⚙️ Umwandeln...",
"⚙️ 编码中...",
"⚙️ Кодируем...",
"⚙️ Codificando...",
@@ -365,7 +365,7 @@ function getTranslation(key, langIndex) {
],
"btnEncodeFailedConvert": [
"💔 Encoding failed",
"💔 Kodierung fehlgeschlagen",
"💔 Umwandeln fehlgeschlagen",
"💔 编码失败",
"💔 Кодирование не удалось",
"💔 Falló la codificación",
@@ -375,7 +375,7 @@ function getTranslation(key, langIndex) {
],
"btnEncodeSuccessConvert": [
"💚 Encoded!",
"💚 Kodiert!",
"💚 Umgewandelt!",
"💚 已编码!",
"💚 Закодировано!",
"💚 ¡Codificado!",
@@ -385,7 +385,7 @@ function getTranslation(key, langIndex) {
],
"btnDecodeWorkingConvert": [
"⚙️ Decoding...",
"⚙️ Dekodieren...",
"⚙️ Umwandeln...",
"⚙️ 解码中...",
"⚙️ Декодируем...",
"⚙️ Decodificando...",
@@ -395,7 +395,7 @@ function getTranslation(key, langIndex) {
],
"btnDecodeFailedConvert": [
"💔 Decoding failed",
"💔 Dekodierung fehlgeschlagen",
"💔 Umwandeln fehlgeschlagen",
"💔 解码失败",
"💔 Декодирование не удалось",
"💔 Falló la decodificación",
@@ -405,7 +405,7 @@ function getTranslation(key, langIndex) {
],
"btnDecodeSuccessConvert": [
"💚 Decoded!",
"💚 Dekodiert!",
"💚 Umgewandelt!",
"💚 已解码!",
"💚 Декодировано!",
"💚 ¡Decodificado!",
@@ -839,7 +839,7 @@ function getTranslation(key, langIndex) {
if (translations[key]) {
return translations[key][langIndex];
} else {
// Return the key itself if translation is not found
return key;
// Return english if translation is not found
return translations[0];
}
}
Loading
Oops, something went wrong.

0 comments on commit 82e37a4

Please sign in to comment.