본문 바로가기

javascript

자바스크립트로 이미지 암호화 복호화 하기

728x90

자바스크립트로 이미지를 불러와 암호화 복호화를 할 수 있습니다.

Encrypt and Decrypt Image

시크릿키를 입력받고 이미지 파일을 선택합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Encrypt and Decrypt Image</title>
    <style>
        body {
            font-family: 'Arial', sans-serif; /* 기본 폰트 설정 */
            padding: 20px; /* 바디 패딩 */
            display: flex;
            flex-direction: column;
            align-items: center; /* 중앙 정렬 */
        }
        #fileInput {
            margin-bottom: 10px; /* 파일 입력과 버튼 사이의 간격 */
        }
        input {
            width: 100%;
            margin-bottom: 10px;
            padding: 10px;
            font-size: 16px;
        }
        button {
            width: 100%; /* 버튼 너비 전체 */
            padding: 15px; /* 버튼 패딩 */
            margin-bottom: 10px; /* 버튼 간의 간격 */
            font-size: 16px; /* 폰트 사이즈 */
            cursor: pointer; /* 커서 포인터 */
            background-color: #007BFF; /* 배경색 */
            color: white; /* 텍스트 색상 */
            border: none; /* 테두리 없음 */
            border-radius: 5px; /* 둥근 테두리 */
        }
        button:hover {
            background-color: #0056b3; /* 호버 시 배경색 변경 */
        }
        #displayImage {
            max-width: 100%; /* 이미지 최대 너비 설정 */
            height: auto; /* 높이 자동 조절 */
            margin-top: 20px; /* 이미지 상단 여백 */
        }
        .box {
            max-width: 100vw;
        }
    </style>
</head>
<body>
    <div class="box">
        <input type="text" id="secretKeyInput" placeholder="Enter secret key" />
        <input type="file" id="fileInput">
        <button id="encryptButton">Encrypt and Download</button>
        <button id="decryptButton">Decrypt and View</button>
        <img id="displayImage" style="display: none;">
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.js"></script>
    <script>

        function getSecretKey() {
            return document.getElementById('secretKeyInput').value;
        }

        /** 파일 입력을 처리하고 콜백에 결과를 전달하는 함수 */
        function handleFileInput(file, callback) {
            const reader = new FileReader();
            reader.onload = function(event) {
                callback(event.target.result);
            };
            reader.readAsArrayBuffer(file);
        }

        document.getElementById('encryptButton').addEventListener('click', function() {
            processFile(encryptAndDownload);
        });

        document.getElementById('decryptButton').addEventListener('click', function() {
            processFile(decryptAndDisplay);
        });

        /* 파일 처리를 위한 함수를 선택하고 실행하는 함수 */
        function processFile(processFunction) {
            const fileInput = document.getElementById('fileInput');
            if (fileInput.files.length === 0) {
                alert('Please select a file first!');
                return;
            }
            const file = fileInput.files[0];
            handleFileInput(file, data => processFunction(data, file.name));
        }

        /* 선택된 파일 데이터를 암호화하고 다운로드하는 함수 */
        function encryptAndDownload(data, filename) {
            const wordArray = CryptoJS.lib.WordArray.create(data);
            const secretKey = getSecretKey();
            if (!secretKey) {
                alert('Please enter a secret key!');
                return;
            }
            const encryptedData = CryptoJS.AES.encrypt(wordArray, secretKey).toString();
            
            // 파일명 인코딩 (확장자 포함)
            const encodedFilename = btoa(filename).replace(/=/g, '');
            
            // 암호화된 데이터와 파일명을 함께 저장
            const saveData = JSON.stringify({
                filename: encodedFilename,
                data: encryptedData
            });

            // 확장자 없이 저장
            downloadFile(saveData, 'encrypted_' + encodedFilename);
        }

        function decryptAndDisplay(data, filename) {
            try {
                // 데이터를 문자열로 변환
                const jsonString = new TextDecoder().decode(data);
                // JSON 파싱
                const parsedData = JSON.parse(jsonString);
                const encryptedData = parsedData.data;
                const encodedFilename = parsedData.filename;

                const secretKey = getSecretKey();
                    if (!secretKey) {
                        alert('Please enter a secret key!');
                        return;
                    }

                // 복호화
                const decryptedData = CryptoJS.AES.decrypt(encryptedData, secretKey);
                const typedArray = convertWordArrayToUint8Array(decryptedData);

                // 파일명 디코딩
                const decodedFilename = atob(encodedFilename);

                // MIME 타입 추정
                const mimeType = getMimeType(decodedFilename);
                
                const blob = new Blob([typedArray], {type: mimeType});
                displayImage(blob, decodedFilename);
            } catch (error) {
                console.error('Decryption error:', error);
                alert('Decryption failed. Please check if the file is correctly encrypted.');
            }
        }

        function handleFileInput(file, callback) {
            const reader = new FileReader();
            reader.onload = function(event) {
                callback(event.target.result, file.name);
            };
            reader.readAsArrayBuffer(file);
        }

        // 파일 다운로드 함수 수정
        function downloadFile(data, filename) {
            const blob = new Blob([data], {type: 'application/octet-stream'});
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove();
        }

        // MIME 타입 추정 함수 (간단한 예시)
        function getMimeType(filename) {
            const ext = filename.split('.').pop().toLowerCase();
            const mimeTypes = {
                'jpg': 'image/jpeg',
                'jpeg': 'image/jpeg',
                'png': 'image/png',
                'gif': 'image/gif',
                // 다른 확장자에 대한 MIME 타입 추가
            };
            return mimeTypes[ext] || 'application/octet-stream';
        }

        /* 생성된 데이터를 사용하여 파일을 다운로드하는 함수 */
        function downloadFile(data, filename) {
            const blob = new Blob([data], {type: 'text/plain'});
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove();
        }

        /* CryptoJS에서 생성된 WordArray를 Uint8Array로 변환하는 함수 */
        function convertWordArrayToUint8Array(wordArray) {
            const arrayOfWords = wordArray.hasOwnProperty("words") ? wordArray.words : [];
            const length = wordArray.hasOwnProperty("sigBytes") ? wordArray.sigBytes : arrayOfWords.length * 4;
            let uInt8Array = new Uint8Array(length);
            let byteOffset = 0;

            arrayOfWords.forEach(word => {
                for (let j = 24; j >= 0; j -= 8) {
                    uInt8Array[byteOffset++] = (word >> j) & 0xff;
                }
            });

            return uInt8Array;
        }

        /* Blob 데이터를 사용하여 웹 페이지에 이미지를 표시하는 함수 */
        function displayImage(blob, filename) {
            const url = window.URL.createObjectURL(blob);
            const img = document.getElementById('displayImage');
            img.src = url;
            img.style.display = 'block';
            img.alt = filename; // 파일명을 alt 속성에 설정
        }
    </script>
</body>
</html>

=========

=========

=========

728x90