JavaScript dize şifreleme ve şifre çözme?


153

JavaScript kullanarak istemci tarafında bilgileri şifreleyecek ve şifresini çözecek kişisel kullanım için küçük bir uygulama oluşturmakla ilgileniyorum. Şifrelenmiş bilgiler bir sunucudaki bir veritabanında saklanır, ancak hiçbir zaman şifresi çözülmez.

Süper duper güvenli olması gerekmiyor, ancak şu anda kesintisiz bir algoritma kullanmak istiyorum.

İdeal olarak şöyle bir şey yapabilirdim

var gibberish = encrypt(string, salt, key);

kodlanmış dizeyi ve

var sensical = decrypt(gibberish, key);

daha sonra kodunu çözmek için.

Şimdiye kadar bunu gördüm: http://bitwiseshiftleft.github.io/sjcl/

Bakmam gereken başka kütüphaneler var mı?




10
Burada bazı terminoloji kapalı, İşte basit bir sürüm 1. Tuzlar, karıştırılan bilgilere (genellikle şifreler) eklenir. Amaçları karmayı tuzsuzdan farklı kılmaktır. Bu, veritabanınız saldırıya uğradığında ve karma kullanıcı parolalarının çıkması durumunda karmaların önceden oluşturulduğundan faydalıdır. 2. Karma, girdiyi çıktıya çeviren tek yönlü bir işlemdir. Kolayca tersine çevrilemez veya geri alınamaz. 3. Kodlama şifreleme değildir. base64_encode, urlencode vb
des

Yanıtlar:


160

 var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
//U2FsdGVkX18ZUVvShFSES21qHsQEqZXMxQ9zgHy+bu0=

var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");
//4d657373616765


document.getElementById("demo1").innerHTML = encrypted;
document.getElementById("demo2").innerHTML = decrypted;
document.getElementById("demo3").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
Full working sample actually is:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js" integrity="sha256-/H4YS+7aYb9kJ5OKhFYPUjSJdrtV6AeyJOtTkw6X72o=" crossorigin="anonymous"></script>

<br><br>
<label>encrypted</label>
<div id="demo1"></div>
<br>

<label>decrypted</label>
<div id="demo2"></div>

<br>
<label>Actual Message</label>
<div id="demo3"></div>


8
Şifreli aslında bir nesnedir, ancak dizeyi almak için passwordted.toString () yöntemini çağırabilirsiniz. Bu dizeyi daha sonra şifresini çözebileceksiniz
Tomas Kirda

9
Ama Gizli parolayı nasıl güvenceye alabiliriz?
duykhoa

9
Kripto js arşivlenmiş bir proje gibi görünüyor. Github'da bir klon var: github.com/sytelus/CryptoJS ancak iki yıl içinde güncellenmedi. Bu hala js şifreleme için en iyi seçenek mi?
syonip

2
Ben bu ile gitmek istiyorum: github.com/brix/crypto-js NPM üzerinden de mevcuttur
Tomas Kirda

1
@stom nasıl ve nerede sakladığınıza bağlıdır. Bir tarayıcıda saklamanın gerçekten güvenli bir yolu olup olmadığını bilmiyorum. Sunucudan isteyin ve bellekte saklayın.
Tomas Kirda

62

Peki ya CryptoJS dersiniz ?

Çok fazla işlevselliğe sahip sağlam bir kripto kütüphanesi. Hasherler, HMAC, PBKDF2 ve şifreleri uygular. Bu durumda ihtiyacınız olan şifrelerdir. Projenin ana sayfasındaki hızlı başlangıç ​​quide'sini kontrol edin.

AES ile benzer bir şey yapabilirsiniz:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>

<script>
    var encryptedAES = CryptoJS.AES.encrypt("Message", "My Secret Passphrase");
    var decryptedBytes = CryptoJS.AES.decrypt(encryptedAES, "My Secret Passphrase");
    var plaintext = decryptedBytes.toString(CryptoJS.enc.Utf8);
</script>

Güvenliğe gelince, yazdığım anda AES algoritmasının kırılmamış olduğu düşünülüyor

Düzenle :

Çevrimiçi URL kapalı görünüyor ve indirilen dosyaları aşağıda verilen bağlantıdan şifreleme için kullanabilir ve ilgili dosyaları uygulamanın kök klasörüne yerleştirebilirsiniz.

https://code.google.com/archive/p/crypto-js/downloads

veya https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js gibi diğer CDN'leri kullandı


Toplamalar ve klasör 3.1.2 altındaki bileşenler arasındaki fark nedir?
Kanagavelu Sugumar

Biraz oynadıktan sonra bileşenler ayrılmış kısımlardır. Çalışması için hangi bileşenlerin (ve hangi sırayla) alınacağını bilmeniz gerekir. Toplama dosyaları, yalnızca bir komut dosyası başvurusu ile çalışmasını sağlamak için gereken her şeyi içerir (zor iş zaten yapıldığından çok daha iyi).
shahar eldad

2
Ancak Gizli parolayı nasıl güvence altına alabiliriz?
shaijut

@shaijut Yapmazsın. Düz metni şifrelerken / şifresini çözerken RAM dışında hiçbir yere kaydetmezsiniz. Parola yalnızca kullanıcının beyninde (veya bir şifre yöneticisinde)
saklanmalıdır

39

Güvenli olmayan ama basit bir metin şifreleme / şifre çözme aracı oluşturdum. Herhangi bir harici kütüphaneye bağımlılık yok.

Bunlar fonksiyonlar

const cipher = salt => {
    const textToChars = text => text.split('').map(c => c.charCodeAt(0));
    const byteHex = n => ("0" + Number(n).toString(16)).substr(-2);
    const applySaltToChar = code => textToChars(salt).reduce((a,b) => a ^ b, code);

    return text => text.split('')
        .map(textToChars)
        .map(applySaltToChar)
        .map(byteHex)
        .join('');
}

const decipher = salt => {
    const textToChars = text => text.split('').map(c => c.charCodeAt(0));
    const applySaltToChar = code => textToChars(salt).reduce((a,b) => a ^ b, code);
    return encoded => encoded.match(/.{1,2}/g)
        .map(hex => parseInt(hex, 16))
        .map(applySaltToChar)
        .map(charCode => String.fromCharCode(charCode))
        .join('');
}

Ve bunları aşağıdaki gibi kullanabilirsiniz:

// To create a cipher
const myCipher = cipher('mySecretSalt')

//Then cipher any text:
myCipher('the secret string')   // --> "7c606d287b6d6b7a6d7c287b7c7a61666f"

//To decipher, you need to create a decipher and use it:
const myDecipher = decipher('mySecretSalt')
myDecipher("7c606d287b6d6b7a6d7c287b7c7a61666f")    // --> 'the secret string'

5
let myDecipher = deşifre ('CartelSystem') - Bu tuz da ipi deşifre eder. 'MySecretSalt' kelimesini tam olarak bilmek zorunda değilsiniz
Dror Bar

Ayrıca, şifre çözücüdeki saltChars kullanılmıyor mu?
Dror Bar

1
Birisi körü körüne kullanıyor başka bir yazı let. 😒︎
John

1
Bu a) süper kırık ve güvensiz değil mi ve b) 'tuz' aslında tuzların özel olması beklenmediği için 'gizli anahtarınız mı? Bu eğlenceli kod herhangi bir gerçek dünya kullanımı için tasarlanmamış herhangi bir yorum yapmadan böyle kod göndermek çok tehlikeli olduğunu düşünüyorum. Yukarı oyların miktarı endişe vericidir. crypto.stackexchange.com/questions/11466/…
lschmierer

1
En azından ses kripto kullanıyorlar. Ne yapıyorsun temelde (her karakter için aynı anahtarı uygulayarak) bir Sezar Chipher olan en.wikipedia.org/wiki/Caesar_cipher#Breaking_the_cipher ... Ben ise bir şey "gizli" olarak adlandırılan aşikardır olmasını bekliyoruz diğer cevaplar ile ilgili olarak gizli tutulması bekleniyor (kullanıcı tarafından)
lschmierer

19

SJCL, CryptoJS ve / veya WebCrypto'dan yararlanan mevcut cevaplar mutlaka yanlış değildir, ancak başlangıçta şüphelenebileceğiniz kadar güvenli değildir. Genellikle libsodium kullanmak istersiniz . Önce nedenini sonra nasıl olduğunu açıklayacağım.

Neden SJCL, CryptoJS, WebCrypto, vb?

Kısa cevap: Şifrelemenizin gerçekten güvenli olması için, bu kütüphaneler çok fazla seçim yapmanızı bekler, örneğin blok şifreleme modu (CBC, CTR, GCM; listelediğim üçünden hangisinin güvenli olduğunu söyleyemiyorsanız) Kullanım ve hangi kısıtlamaları altında, istediğiniz bu tür yük olmamalıdır hiç ).

İş unvanınız kriptografi mühendisi olmadığı sürece , oranları güvenli bir şekilde uygulamanıza karşı yığılmış.

Neden CryptoJS'den Kaçının?

CryptoJS bir avuç yapı taşı sunar ve bunları nasıl güvenli bir şekilde kullanacağınızı bilmenizi bekler. Hatta varsayılan olarak CBC moduna ( arşivlenmiş ) geçer.

CBC modu neden kötü?

AES-CBC güvenlik açıkları hakkındaki bu yazıyı okuyun .

WebCrypto'dan Neden Kaçının?

WebCrypto, kriptografi mühendisliğine dik amaçlar için komite tarafından tasarlanan bir potluck standardıdır. Özellikle, WebCrypto'nun güvenlik sağlamak yerine Flash'ın yerini alması amaçlanmıştır .

Neden SJCL'den Kaçının?

SJCL'nin genel API ve belgeleri, kullanıcılara verileri hatırlanan bir şifreyle şifrelemelerini ister. Bu nadiren, eğer varsa, gerçek dünyada yapmak istediğiniz şeydir.

Ayrıca: Varsayılan PBKDF2 yuvarlak sayısı kabaca 86 kat daha küçüktür . AES-128-CCM muhtemelen iyidir.

Yukarıdaki üç seçenekten SJCL'nin gözyaşı ile bitmesi en az muhtemel olanıdır. Ancak daha iyi seçenekler var.

Libsodium neden daha iyi?

Şifreleme modları menüsü, karma işlevleri ve diğer gereksiz seçenekler arasında seçim yapmanız gerekmez. Sen asla Parametrelerinizi berbat ve protokolden tüm güvenlik kaldırarak riske .

Bunun yerine, libsodium size maksimum güvenlik ve minimalist API'ler için ayarlanmış basit seçenekler sunar.

  • crypto_box()/ crypto_box_open()kimliği doğrulanmış ortak anahtar şifrelemesi sunar.
    • Söz konusu algoritma X25519 (Curve25519 üzerinden ECDH) ve XSalsa20-Poly1305'i birleştiriyor, ancak güvenli bir şekilde kullanmak için bunu bilmenize (hatta umursamanıza) gerek yok
  • crypto_secretbox()/ crypto_secretbox_open()paylaşılan anahtar kimlik doğrulamalı şifreleme sunar.
    • Söz konusu algoritma XSalsa20-Poly1305'tir, ancak bilmenize / bakmanıza gerek yoktur

Ek olarak, libsodium'un düzinelerce popüler programlama dilinde bağlamaları vardır , bu nedenle libsodium'un başka bir programlama yığını ile birlikte çalışmayı denediğinde çalışması muhtemeldir . Ayrıca, libsodium güvenlikten ödün vermeden çok hızlı olma eğilimindedir.

JavaScript Libsodium Nasıl Kullanılır?

İlk olarak, bir şeye karar vermelisiniz:

  1. Sadece verileri şifrelemek / şifresini çözmek (ve yine de bir şekilde düz metinleri veritabanı sorgularında güvenli bir şekilde kullanmak) ve ayrıntılar hakkında endişelenmek istemiyor musunuz? Veya...
  2. Belirli bir protokol uygulamanız gerekiyor mu?

Birinci seçeneği seçtiyseniz , olsun CipherSweet.js .

Dokümantasyon çevrimiçi olarak mevcuttur . EncryptedFieldçoğu kullanım durumu için yeterlidir, ancak şifrelemek istediğiniz birçok farklı alanınız varsa EncryptedRowve EncryptedMultiRowsAPI'leri daha kolay olabilir.

CipherSweet ile, nonce / IV'ün güvenli bir şekilde kullanmak için ne olduğunu bilmenize bile gerek yoktur .

Buna ek olarak, bu, şifreleme boyutu üzerinden içerikler hakkında gerçekleri sızdırmadan işler int/ floatşifreleme yapar.

Aksi takdirde, isteyeceksiniz sodyum-artı , çeşitli libsodium sarmalayıcılara kullanıcı dostu bir arayüzü olduğunu. Sodium-Plus, denetlemesi kolay ve nedeni olan performanslı, asenkron, platformlar arası kod yazmanıza olanak tanır.

Sodyum artıyı kurmak için çalıştırın ...

npm install sodium-plus

Şu anda tarayıcı desteği için herkese açık bir CDN yok. Bu yakında değişecek. Ancak, yakalayabilir sodium-plus.min.jsgelen son Github sürümü de gerekirse.

const { SodiumPlus } = require('sodium-plus');
let sodium;

(async function () {
    if (!sodium) sodium = await SodiumPlus.auto();
    let plaintext = 'Your message goes here';
    let key = await sodium.crypto_secretbox_keygen();
    let nonce = await sodium.randombytes_buf(24);
    let ciphertext = await sodium.crypto_secretbox(
        plaintext,
        nonce,
        key    
    );
    console.log(ciphertext.toString('hex'));

    let decrypted = await sodium.crypto_secretbox_open(
        ciphertext,
        nonce,
        key
    );

    console.log(decrypted.toString());
})();

Sodyum artı belgeleri Github'da bulunabilir.

Adım adım bir eğitici isterseniz , bu dev.to makalesinde aradığınızı bulabilirsiniz.



5

Bunlardan herhangi birini uygulamadan önce lütfen Scott Arciszewski'nin cevabına bakınız .

Çok az veya hiç güvenlik bilgim olmadığından (aşağıdaki API'yı kötüye kullanma şansım yüksek olduğundan) paylaşmak üzere olduğum şeylere çok dikkat etmenizi istiyorum , bu yüzden bu yanıtı güncellemekten memnuniyet duyarım topluluğun yardımıyla .

@Richardtallent onun belirtildiği gibi cevap bu örnek standardını kullanır, böylece, Web Kripto API için destek var. Bu yazı itibariyle, küresel tarayıcı desteğinin% 95,88'i var .

Web Kripto API'sını kullanarak bir örnek paylaşacağım

Devam etmeden önce lütfen not edin ( MDN'den alıntı ):

Bu API bir dizi düşük seviyeli şifreleme ilkesi sağlar. Bu var bunları kötüye kullanma çok kolay ve tuzaklar dahil olabilir çok ince .

Temel şifreleme işlevlerini doğru şekilde kullandığınızı varsaysanız bile, güvenli anahtar yönetimi ve genel güvenlik sistemi tasarımının doğru olması son derece zordur ve genellikle uzman güvenlik uzmanlarının alanıdır.

Güvenlik sistemi tasarımı ve uygulamasındaki hatalar, sistemin güvenliğini tamamen etkisiz hale getirebilir.

Ne yaptığınızı bildiğinizden emin değilseniz, muhtemelen bu API'yı kullanmamalısınız .

Güvenliğe çok saygı duyuyorum ve MDN'den ek parçalar bile cesur oldum ...

Şimdi, gerçek örneğe uyarıldınız ...


JSFiddle:

Burada bulundu: https://jsfiddle.net/superjose/rm4e0gqa/5/

Not:

awaitAnahtar kelimelerin kullanımına dikkat edin . Bir asyncfonksiyonun içinde kullanın veya .then()ve kullanın .catch().

Anahtarı oluşturun:

// https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey
// https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
// https://github.com/diafygi/webcrypto-examples#rsa-oaep---generatekey
    const stringToEncrypt = 'https://localhost:3001';
    // https://github.com/diafygi/webcrypto-examples#rsa-oaep---generatekey
    // The resultant publicKey will be used to encrypt
    // and the privateKey will be used to decrypt. 
    // Note: This will generate new keys each time, you must store both of them in order for 
    // you to keep encrypting and decrypting.
    //
    // I warn you that storing them in the localStorage may be a bad idea, and it gets out of the scope
    // of this post. 
    const key = await crypto.subtle.generateKey({
      name: 'RSA-OAEP',
      modulusLength: 4096,
      publicExponent:  new Uint8Array([0x01, 0x00, 0x01]),
      hash: {name: 'SHA-512'},
      
    }, true,
    // This depends a lot on the algorithm used
    // Go to https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
    // and scroll down to see the table. Since we're using RSA-OAEP we have encrypt and decrypt available
    ['encrypt', 'decrypt']);

    // key will yield a key.publicKey and key.privateKey property.

şifrele:

    const encryptedUri = await crypto.subtle.encrypt({
      name: 'RSA-OAEP'
    }, key.publicKey, stringToArrayBuffer(stringToEncrypt))
    
    console.log('The encrypted string is', encryptedUri);

azalmak

   const msg = await  crypto.subtle.decrypt({
      name: 'RSA-OAEP',
    }, key.privateKey, encryptedUri);
    console.log(`Derypted Uri is ${arrayBufferToString(msg)}`)

ArrayBuffer'ı Dize'den (TypeScript'te Bitti) ileri geri dönüştürme:

  private arrayBufferToString(buff: ArrayBuffer) {
    return String.fromCharCode.apply(null, new Uint16Array(buff) as unknown as number[]);
  }

  private stringToArrayBuffer(str: string) {
    const buff = new ArrayBuffer(str.length*2) // Because there are 2 bytes for each char.
    const buffView = new Uint16Array(buff);
    for(let i = 0, strLen = str.length; i < strLen; i++) {
      buffView[i] = str.charCodeAt(i);
    }
    return buff;
  }

Burada daha fazla örnek bulabilirsiniz (sahip değilim): // https://github.com/diafygi/webcrypto-examples


2

CryptoJS artık desteklenmemektedir. Kullanmaya devam etmek istiyorsanız, şu url'ye geçebilirsiniz:

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>


Toplamalar ve klasör 3.1.2 altındaki bileşenler arasındaki fark nedir?
Kanagavelu Sugumar

1
Kripto, sitelerine girdiğinizde forge kütüphanesini tavsiye ediyor .
Dror Bar

1

SimpleCrypto kullanın

Encrypt () ve decrypt () kullanma

SimpleCrypto'yu kullanmak için, önce gizli anahtarla (şifre) bir SimpleCrypto örneği oluşturun. SimpleCrypto örneği oluşturulurken gizli anahtar parametresi tanımlanmalıdır ZORUNLU.

Verileri şifrelemek ve şifresini çözmek için bir örnekten encrypt () ve decrypt () işlevini kullanın. Bu AES-CBC şifreleme algoritmasını kullanacaktır.

var _secretKey = "some-unique-key";

var simpleCrypto = new SimpleCrypto(_secretKey);

var plainText = "Hello World!";
var chiperText = simpleCrypto.encrypt(plainText);
console.log("Encryption process...");
console.log("Plain Text    : " + plainText);
console.log("Cipher Text   : " + cipherText);
var decipherText = simpleCrypto.decrypt(cipherText);
console.log("... and then decryption...");
console.log("Decipher Text : " + decipherText);
console.log("... done.");

3
SimpleCrypto, kimliği doğrulanmamış AES-CBC kullanır ve bu nedenle seçilen şifreli metin saldırılarına karşı savunmasızdır.
Scott Arciszewski

-6

Basit fonksiyonlar,


function Encrypt(value) 
{
  var result="";
  for(i=0;i<value.length;i++)
  {
    if(i<value.length-1)
    {
        result+=value.charCodeAt(i)+10;
        result+="-";
    }
    else
    {
        result+=value.charCodeAt(i)+10;
    }
  }
  return result;
}
function Decrypt(value)
{
  var result="";
  var array = value.split("-");

  for(i=0;i<array.length;i++)
  {
    result+=String.fromCharCode(array[i]-10);
  }
  return result;
} 

4
Bu kod snippet'i çözüm olsa da, bir açıklama da dahil olmak üzere mesajınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Johan

1
Bu güvenli bir algoritma değildir (Şifrenin anahtar bir parametre almadığını unutmayın) ve kolayca tersine çevrilebilir. OP, üzerinde güvenlik olan bir şey istedi.
Mike S
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.