programing

JavaScript 문자열 암호화 및 암호 해독

kingscode 2022. 10. 30. 18:13
반응형

JavaScript 문자열 암호화 및 암호 해독

JavaScript를 사용하여 클라이언트 측의 정보를 암호화 및 해독할 수 있는 개인용 작은 앱을 만들고 싶습니다.암호화된 정보는 서버의 데이터베이스에 저장되지만 복호화 버전은 저장되지 않습니다.

슈퍼듀퍼 보안은 필요 없지만, 현재 중단되지 않은 알고리즘을 사용하고 싶습니다.

이상적으로는 이런 걸 할 수 있을 것 같아요

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

부호화 문자열을 생성하는 것 같은 것

var sensical = decrypt(gibberish, key);

나중에 해독할 수 있습니다.

지금까지 본 내용: http://bitwiseshiftleft.github.io/sjcl/

제가 봐야 할 다른 도서관은 없나요?

 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>

CryptoJS는 어때?

풍부한 기능을 갖춘 견고한 암호화 라이브러리입니다.해시, HMAC, PBKDF2 및 암호를 구현합니다.이 경우 암호만 있으면 됩니다.프로젝트 홈페이지에서 빠른 시작 쿼드를 확인하십시오.

AES를 사용하여 다음과 같은 작업을 수행할 수 있습니다.

<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>

보안에 관해서입니다만, AES 알고리즘은 작성 시점에서 고장나지 않은 것으로 생각됩니다.

편집:

온라인 URL이 다운된 것 같습니다.다운로드한 파일을 아래 링크에서 암호화하여 해당 파일을 응용 프로그램의 루트 폴더에 저장할 수 있습니다.

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

또는 https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js과 같은 다른 CDN을 사용합니다.

안전하지 않지만 단순한 텍스트 암호/암호 해독 유틸리티를 만들었습니다.외부 라이브러리와의 의존 관계가 없습니다.

기능은 다음과 같습니다.

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('');
}

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

//Then cipher any text:
console.log(myCipher('the secret string'))

//To decipher, you need to create a decipher and use it:
const myDecipher = decipher('mySecretSalt')
console.log(myDecipher("7c606d287b6d6b7a6d7c287b7c7a61666f"))

이 코드는 위의 @Jorgeblom의 답변에 기초하고 있습니다.


@Jorgeblom my man, that small crypto lib:D 소금을 할당하고 다시 불러야 하는 것이 싫어서 살짝 만져봤지만 전반적으로 내 욕구는 완벽하기 때문이다.

const crypt = (salt, text) => {
  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
    .split("")
    .map(textToChars)
    .map(applySaltToChar)
    .map(byteHex)
    .join("");
};

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

그리고 너는 그것을 사용한다.

// encrypting
const encrypted_text = crypt("salt", "Hello"); // -> 426f666665

// decrypting
const decrypted_string = decrypt("salt", "426f666665"); // -> Hello

SJCL, CryptoJ 및/또는 WebCrypto를 활용하는 기존 답변이 반드시 틀린 것은 아니지만, 처음에 생각했던 것만큼 안전하지 않습니다.보통 립소듐을 사용하세요.먼저 이유를 설명하고 그 다음에 방법을 설명하겠습니다.

왜 SJCL, CryptoJ, WebCrypto 등이 없습니까?

간단한 답변:이러한 라이브러리는 암호화를 실제로 안전하게 하기 위해 블록 암호 모드(CBC, CTR, GCM 등)를 너무 많이 선택할 것을 요구하고 있습니다.지금 리스트한 3가지 중 어느 것이 사용하기에 안전한지, 또 어떤 제약조건에서 사용하는지 알 수 없는 경우, 이러한 종류의 선택에 전혀 부담을 가질 필요가 없습니다.

암호화 엔지니어가 아니면 안전하게 구현할 가능성이 높아집니다.

CryptoJ를 피하는 이유

CryptoJS에서는 소수의 빌딩 블록이 제공되므로 안전하게 사용하는 방법을 알고 있어야 합니다.디폴트로는 CBC 모드(아카이브)도 됩니다.

CBC 모드가 나쁜 이유는 무엇입니까?

AES-CBC 취약성에 대한 이 글을 읽어 보십시오.

Web Crypto를 피하는 이유

WebCrypto는 암호화 엔지니어링과 직교하는 목적을 위해 위원회가 설계한 포트럭 표준입니다.특히 WebCrypto는 플래시를 대체하는 것이지 보안을 제공하는 것은 아닙니다.

SJCL을 피하는 이유

SJCL의 공개 API 및 문서에서는 사용자가 기억한 비밀번호를 사용하여 데이터를 암호화해야 합니다.이것은 현실에서 하고 싶은 일이 거의 없습니다.

기타:디폴트 PBKDF2 라운드카운트는 원하는 값의 약 86배입니다.AES-128-CCM이면 충분합니다.

위의 3가지 옵션 중 SJCL이 가장 울 가능성이 낮습니다.하지만 더 나은 선택지가 있습니다.

왜 립소듐이 더 좋은가?

암호 모드, 해시 함수 및 기타 불필요한 옵션 메뉴를 선택할 필요가 없습니다.매개 변수를 망치고 프로토콜에서 모든 보안을 제거할 위험이 없습니다.

대신 libsodium은 최대한의 보안과 미니멀리즘 API를 위해 조정된 단순한 옵션만 제공합니다.

  • crypto_box()crypto_box_open()이치
    • 문제의 알고리즘은 X25519(ECDH over Curve25519)와 XSalsa20-Poly1305를 조합하고 있습니다만, 안전하게 사용하기 위해서 알고 있을 필요는 없습니다(또는 신경 쓸 필요도 없습니다).
  • crypto_secretbox()crypto_secretbox_open()공유 키 인증 암호화를 제공합니다.
    • 문제가 되고 있는 알고리즘은 XSalsa20-Poly1305입니다만, 알 필요가 없습니다.

또한 립소듐은 수십 의 인기 있는 프로그래밍 언어로 바인딩되어 있기 때문에 다른 프로그래밍 스택과 상호 운용하려고 할 때 립소듐이 작동할 가능성이 높습니다.또한 립소듐은 보안을 해치지 않고 매우 빠른 경향이 있습니다.

JavaScript에서 Libsodium을 사용하는 방법

먼저 한 가지를 결정해야 합니다.

  1. 데이터 암호화/복호화(및 데이터베이스 쿼리에서 일반 텍스트를 안전하게 사용)만 하고 자세한 내용은 신경 쓰지 않으시겠습니까?아니면...
  2. 특정 프로토콜을 구현해야 합니까?

번째 옵션을 선택한 경우 CipherSweet.js를 가져옵니다.

매뉴얼은 온라인으로 입수할 수 있습니다. EncryptedField대부분의 사용 예에서는 충분하지만EncryptedRow그리고.EncryptedMultiRows암호화하려는 필드가 여러 개 있는 경우 API가 더 쉬울 수 있습니다.

CipherSweet을 사용하면 어떤 난스인지필요도 없습니다.IV는 안전하게 사용하는 것입니다.

또한 이 핸들은int/float암호문 크기를 통해 내용에 대한 사실을 유출하지 않고 암호화를 수행할 수 있습니다.

그렇지 않으면, 다양한 립소듐 포장지의 사용하기 쉬운 프런트 엔드인 나트륨 플러스가 필요할 것입니다.Sodium-Plus를 사용하면 성능, 비동기, 교차 플랫폼 코드를 쉽게 작성하여 감사 및 추론할 수 있습니다.

나트륨 플러스를 설치하려면, 간단히 실행...

npm install sodium-plus

현재 브라우저 지원을 위한 공개 CDN은 없습니다.이건 곧 바뀔 거예요.하지만, 당신은 그것을 잡을 수 있다.sodium-plus.min.js최신 Github 릴리즈를 참조하십시오.

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());
})();

나트륨 플러스에 대한 설명서는 Github에서 구할 수 있습니다.

단계별 튜토리얼이 필요한 경우 이 dev.to 기사를 참조하십시오.

현재 최신 브라우저는crypto.subtleAPI: AES-CBC, AES-CTR, AES-GCM 또는 RSA-OAEP 중 하나의 방식을 사용하여 네이티브 암호화 및 복호화 기능(async not less!)을 제공합니다.

https://www.w3.org/TR/WebCryptoAPI/ #dfn-Crypto

이 중 하나를 구현하기 전에 Scott Archiszewski의 답변을 참조하십시오.

저는 보안에 관한 지식이 거의 없거나 전혀 없기 때문에(아래 API를 잘못 사용하고 있을 가능성이 높기 때문에) 커뮤니티의 도움을 받아답변을 갱신해 주시면 감사하겠습니다.

@richardtalent가 답변에서 언급했듯이 Web Crypto API가 지원되므로 이 예에서는 표준을 사용합니다.이 글에서는 95.88%의 글로벌 브라우저 지원이 이루어지고 있습니다.

Web Crypto API를 사용한 예를 공유하겠습니다.

계속 진행하기 전에 (MDN에서 인용)에 주의해 주십시오.

이 API는 여러 하위 수준의 암호화 프리미티브를 제공합니다.그것들을 오용하는 것은 매우 쉽고, 관련된 함정매우 미묘할 수 있습니다.

기본적인 암호화 기능을 올바르게 사용하고 있다고 해도, 시큐어 키 관리와 시큐러티 시스템 전체의 설계는 매우 곤란하고, 통상은 시큐러티 전문가의 영역입니다.

보안 시스템 설계 및 구현에 오류가 있으면 시스템 보안이 완전히 비활성화될 수 있습니다.

자신이 무엇을 하고 있는지 확실하지 않다면 API를 사용하지 않는 것이 좋습니다.

저는 보안을 매우 존중하고 MDN의 추가 부품도 과감하게 처리했습니다.경고받았잖아

아, 아, 아, 아, 아, 아, 아...


JSFiddle:

검색처: https://jsfiddle.net/superjose/rm4e0gqa/5/

참고:

「 」의 .await키워드를 지정합니다.async 또는 를 사용합니다..then() ★★★★★★★★★★★★★★★★★」.catch().

키를 생성합니다.

// 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.

암호화:

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


복호화

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

ArrayBuffer를 String에서 앞뒤로 변환(TypeScript에서 실행):

  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;
  }

자세한 예는 이쪽에서 보실 수 있습니다(저는 소유자가 아닙니다). // https://github.com/diafygi/webcrypto-examples

crypt.subtle AES-GCM, 자체 포함, 테스트 완료:

async function aesGcmEncrypt(plaintext, password)

async function aesGcmDecrypt(ciphertext, password) 

https://gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a

이러한 기능을 사용할 수 있습니다.암호화를 위한 첫 번째 기능은 매우 간단합니다.따라서 함수를 호출하여 암호화하고 싶은 텍스트를 전송하고 암호화의 결과를 가져옵니다.With AES 함수는 다음과 같이 복호화 함수로 전송합니다.

const CryptoJS = require("crypto-js");


   //The Function Below To Encrypt Text
   const encryptWithAES = (text) => {
      const passphrase = "My Secret Passphrase";
      return CryptoJS.AES.encrypt(text, passphrase).toString();
    };
    //The Function Below To Decrypt Text
    const decryptWithAES = (ciphertext) => {
      const passphrase = "My Secret Passphrase";
      const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase);
      const originalText = bytes.toString(CryptoJS.enc.Utf8);
      return originalText;
    };

  let encryptText = encryptWithAES("YAZAN"); 
  //EncryptedText==>  //U2FsdGVkX19GgWeS66m0xxRUVxfpI60uVkWRedyU15I= 

  let decryptText = decryptWithAES(encryptText);
  //decryptText==>  //YAZAN 

CryptoJ는 지원되지 않게 되었습니다.계속 사용하려면 다음 URL로 전환할 수 있습니다.

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

업데이트 2021년 12월

MDN Web Docs에서 제공하는 crypto api를 사용합니다.

https://developer.mozilla.org/en-US/docs/Web/API/Crypto


구답

Simple Crypto 사용

encrypt() 및 decrypt() 사용

SimpleCrypto를 사용하려면 먼저 개인 키(패스워드)를 사용하여 SimpleCrypto 인스턴스를 만듭니다.SimpleCrypto 인스턴스를 생성할 때 개인 키 매개 변수를 정의해야 합니다.

데이터를 암호화 및 복호화하려면 인스턴스에서 encrypt() 및 decrypt() 함수를 사용합니다.AES-CBC 암호화 알고리즘을 사용합니다.

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.");

심플한 기능:

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;
} 

언급URL : https://stackoverflow.com/questions/18279141/javascript-string-encryption-and-decryption

반응형