본문으로 건너뛰기

syn.$c

개요

syn.$c는 HandStack 웹 애플리케이션에서 다양한 암호화, 해시, 인코딩 기능을 제공합니다. Base64 인코딩, SHA-256 해시, AES/RSA 암호화, HMAC 생성, 문자열 압축 등의 보안 관련 기능을 포함합니다.

주요 기능

Base64 인코딩/디코딩

base64Encode(val)

문자열을 Base64로 인코딩합니다.

구문

syn.$c.base64Encode(val)

매개변수

  • val (String): 인코딩할 문자열

반환값

  • String: Base64 인코딩된 문자열

예제

var originalText = 'Hello, World! 안녕하세요!';
var encoded = syn.$c.base64Encode(originalText);
console.log('인코딩 결과:', encoded);

// 출력: SGVsbG8sIFdvcmxkISDslYjrhZXtlZjshLjsmpQh

base64Decode(val)

Base64 문자열을 디코딩합니다.

구문

syn.$c.base64Decode(val)

매개변수

  • val (String): Base64 인코딩된 문자열

반환값

  • String: 디코딩된 원본 문자열

예제

var encodedText = 'SGVsbG8sIFdvcmxkISDslYjrhZXtlZjshLjsmpQh';
var decoded = syn.$c.base64Decode(encodedText);
console.log('디코딩 결과:', decoded);

// 출력: Hello, World! 안녕하세요!

UTF-8 인코딩/디코딩

utf8Encode(plainString)

문자열을 UTF-8 바이트 배열로 인코딩합니다.

구문

syn.$c.utf8Encode(plainString)

매개변수

  • plainString (String): 인코딩할 문자열

반환값

  • Uint8Array: UTF-8 바이트 배열

예제

var text = '한글 텍스트';
var utf8Bytes = syn.$c.utf8Encode(text);
console.log('UTF-8 바이트:', utf8Bytes);

utf8Decode(encodeString)

UTF-8 바이트 문자열을 디코딩합니다.

구문

syn.$c.utf8Decode(encodeString)

매개변수

  • encodeString (String): UTF-8 인코딩된 바이트 문자열 (콤마로 구분)

반환값

  • String: 디코딩된 문자열

해시 함수

sha256(s)

문자열의 SHA-256 해시를 계산합니다.

구문

syn.$c.sha256(s)

매개변수

  • s (String): 해시할 문자열

반환값

  • String: SHA-256 해시값 (16진수)

예제

var text = 'Hello World';
var hash = syn.$c.sha256(text);
console.log('SHA-256 해시:', hash);

// 비밀번호 해싱
var password = 'user-password';
var hashedPassword = syn.$c.sha256(password + 'salt-string');
console.log('해시된 비밀번호:', hashedPassword);

sha(message, algorithms)

다양한 해시 알고리즘을 사용하여 해시를 생성합니다.

구문

syn.$c.sha(message, algorithms?)

매개변수

  • message (String): 해시할 메시지
  • algorithms (String, 선택사항): 해시 알고리즘 (기본값: 'SHA-256')
    • 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512' 등

반환값

  • Promise<String>: 해시값 (16진수)

예제

async function generateHashes() {
var message = 'Hello World';

var sha1 = await syn.$c.sha(message, 'SHA-1');
var sha256 = await syn.$c.sha(message, 'SHA-256');
var sha512 = await syn.$c.sha(message, 'SHA-512');

console.log('SHA-1:', sha1);
console.log('SHA-256:', sha256);
console.log('SHA-512:', sha512);
}

generateHashes();

Web Crypto API 지원

isWebCryptoSupported()

Web Crypto API 지원 여부를 확인합니다.

구문

syn.$c.isWebCryptoSupported()

반환값

  • Boolean: Web Crypto API 지원 여부

예제

if (syn.$c.isWebCryptoSupported()) {
console.log('Web Crypto API 지원됨');
// 고급 암호화 기능 사용 가능
} else {
console.log('Web Crypto API 미지원');
// 대체 방법 사용
}

HMAC (Hash-based Message Authentication Code)

generateHMAC(key, message)

HMAC-SHA256 서명을 생성합니다.

구문

syn.$c.generateHMAC(key, message)

매개변수

  • key (String): HMAC 키
  • message (String): 서명할 메시지

반환값

  • Promise<String>: HMAC 서명 (16진수)

예제

async function createHMAC() {
var key = 'secret-key';
var message = 'important message';

var signature = await syn.$c.generateHMAC(key, message);
console.log('HMAC 서명:', signature);

// API 요청 시 무결성 검증용으로 사용
return signature;
}

createHMAC();

verifyHMAC(key, message, signature)

HMAC 서명을 검증합니다.

구문

syn.$c.verifyHMAC(key, message, signature)

매개변수

  • key (String): HMAC 키
  • message (String): 원본 메시지
  • signature (String): 검증할 HMAC 서명

반환값

  • Promise<Boolean>: 서명 유효성 여부

예제

async function verifyMessage() {
var key = 'secret-key';
var message = 'important message';
var receivedSignature = 'received-hmac-signature';

var isValid = await syn.$c.verifyHMAC(key, message, receivedSignature);

if (isValid) {
console.log('메시지 검증 성공');
} else {
console.log('메시지 검증 실패 - 무결성 오류');
}
}

verifyMessage();

RSA 암호화

generateRSAKey()

RSA 키 쌍을 생성합니다.

구문

syn.$c.generateRSAKey()

반환값

  • Promise<CryptoKeyPair>: RSA 공개키/개인키 쌍

예제

async function setupRSAEncryption() {
var keyPair = await syn.$c.generateRSAKey();

console.log('RSA 키 쌍 생성 완료');
console.log('공개키:', keyPair.publicKey);
console.log('개인키:', keyPair.privateKey);

return keyPair;
}

setupRSAEncryption();

exportCryptoKey(cryptoKey, isPublic)

암호화 키를 PEM 형식으로 내보냅니다.

구문

syn.$c.exportCryptoKey(cryptoKey, isPublic)

매개변수

  • cryptoKey (CryptoKey): 내보낼 키
  • isPublic (Boolean): 공개키 여부

반환값

  • Promise<String>: PEM 형식의 키

예제

async function exportKeys() {
var keyPair = await syn.$c.generateRSAKey();

var publicKeyPEM = await syn.$c.exportCryptoKey(keyPair.publicKey, true);
var privateKeyPEM = await syn.$c.exportCryptoKey(keyPair.privateKey, false);

console.log('공개키 PEM:', publicKeyPEM);
console.log('개인키 PEM:', privateKeyPEM);

// 키를 서버나 로컬 스토리지에 저장
localStorage.setItem('publicKey', publicKeyPEM);
localStorage.setItem('privateKey', privateKeyPEM);
}

exportKeys();

rsaEncode(text, publicKey) / rsaDecode(encryptedData, privateKey)

RSA 암호화/복호화를 수행합니다.

예제

async function rsaEncryptionExample() {
// 키 생성
var keyPair = await syn.$c.generateRSAKey();

// 암호화
var plainText = '중요한 기밀 정보';
var encryptedData = await syn.$c.rsaEncode(plainText, keyPair.publicKey);
console.log('암호화된 데이터:', encryptedData);

// 복호화
var decryptedText = await syn.$c.rsaDecode(encryptedData, keyPair.privateKey);
console.log('복호화된 텍스트:', decryptedText);

// 원본과 복호화 결과 비교
console.log('암호화/복호화 성공:', plainText === decryptedText);
}

rsaEncryptionExample();

AES 암호화

aesEncode(text, key, algorithm, keyLength)

AES 암호화를 수행합니다.

구문

syn.$c.aesEncode(text, key, algorithm?, keyLength?)

매개변수

  • text (String): 암호화할 텍스트
  • key (String): 암호화 키
  • algorithm (String, 선택사항): 암호화 알고리즘 (기본값: 'AES-CBC')
  • keyLength (Number, 선택사항): 키 길이 (기본값: 256)

반환값

  • Promise<Object>: 암호화 결과
    • iv: 초기화 벡터 (Base64)
    • encrypted: 암호화된 데이터 (Base64)

aesDecode(encryptedData, key, algorithm, keyLength)

AES 복호화를 수행합니다.

예제

async function aesEncryptionExample() {
var plainText = '비밀 메시지';
var secretKey = 'my-secret-key-123';

// AES 암호화
var encryptResult = await syn.$c.aesEncode(plainText, secretKey);
console.log('암호화 결과:', encryptResult);

// AES 복호화
var decryptedText = await syn.$c.aesDecode(encryptResult, secretKey);
console.log('복호화 결과:', decryptedText);

// 검증
console.log('암호화/복호화 성공:', plainText === decryptedText);
}

aesEncryptionExample();

단순 암호화 (HandStack 전용)

encrypt(value, key) / decrypt(value, key)

HandStack 전용 단순 암호화/복호화 함수입니다.

구문

syn.$c.encrypt(value, key?)
syn.$c.decrypt(value, key?)

매개변수

  • value (String): 암호화/복호화할 값
  • key (String, 선택사항): 암호화 키 (기본값: 시스템 기본 키)

예제

var sensitiveData = '사용자 개인정보';
var customKey = 'myCustomKey';

// 암호화
var encrypted = syn.$c.encrypt(sensitiveData, customKey);
console.log('암호화된 데이터:', encrypted);

// 복호화
var decrypted = syn.$c.decrypt(encrypted, customKey);
console.log('복호화된 데이터:', decrypted);

// 로컬 스토리지에 암호화된 데이터 저장
localStorage.setItem('encryptedUserData', encrypted);

문자열 압축 (LZString)

LZString 압축/압축 해제

문자열을 압축하여 저장 공간을 절약합니다.

예제

// 큰 데이터 압축
var largeData = JSON.stringify({
users: [
{ name: '홍길동', age: 30, address: '서울시 강남구' },
{ name: '김철수', age: 25, address: '부산시 해운대구' },
// ... 많은 데이터
]
});

// 압축
var compressed = syn.$c.LZString.compressToBase64(largeData);
console.log('원본 크기:', largeData.length);
console.log('압축 크기:', compressed.length);
console.log('압축률:', ((1 - compressed.length / largeData.length) * 100).toFixed(2) + '%');

// 압축 해제
var decompressed = syn.$c.LZString.decompressFromBase64(compressed);
console.log('압축 해제 성공:', largeData === decompressed);

// 로컬 스토리지 최적화
localStorage.setItem('compressedData', compressed);

실전 활용 예제

1. 사용자 인증 시스템

async function userAuthenticationSystem() {
// 비밀번호 해싱
function hashPassword(password, salt) {
return syn.$c.sha256(password + salt);
}

// 사용자 등록
async function registerUser(username, password) {
var salt = syn.$l.random(16);
var hashedPassword = hashPassword(password, salt);

var userData = {
username: username,
passwordHash: hashedPassword,
salt: salt,
createdAt: new Date().toISOString()
};

// 암호화하여 저장
var encryptedData = syn.$c.encrypt(JSON.stringify(userData));
localStorage.setItem('user_' + username, encryptedData);

console.log('사용자 등록 완료:', username);
return true;
}

// 사용자 로그인
async function loginUser(username, password) {
var encryptedData = localStorage.getItem('user_' + username);
if (!encryptedData) {
console.log('사용자를 찾을 수 없습니다.');
return false;
}

var decryptedData = syn.$c.decrypt(encryptedData);
var userData = JSON.parse(decryptedData);

var inputPasswordHash = hashPassword(password, userData.salt);

if (inputPasswordHash === userData.passwordHash) {
console.log('로그인 성공:', username);

// 세션 토큰 생성
var sessionToken = await syn.$c.generateHMAC(userData.salt, username + Date.now());
sessionStorage.setItem('sessionToken', sessionToken);

return true;
} else {
console.log('비밀번호가 일치하지 않습니다.');
return false;
}
}

// 사용 예제
await registerUser('testuser', 'mypassword123');
await loginUser('testuser', 'mypassword123');
}

userAuthenticationSystem();

2. 안전한 데이터 전송

async function secureDataTransmission() {
// 클라이언트 측 암호화
async function sendSecureData(data, serverPublicKeyPEM) {
// 서버 공개키 로드
var serverPublicKey = await syn.$c.importCryptoKey(serverPublicKeyPEM, true);

// 데이터 직렬화
var jsonData = JSON.stringify(data);

// RSA로 AES 키 암호화 (하이브리드 암호화)
var aesKey = syn.$l.random(32);
var encryptedAESKey = await syn.$c.rsaEncode(aesKey, serverPublicKey);

// AES로 실제 데이터 암호화
var encryptedData = await syn.$c.aesEncode(jsonData, aesKey);

// HMAC으로 무결성 보장
var signature = await syn.$c.generateHMAC(aesKey, jsonData);

var payload = {
encryptedKey: encryptedAESKey,
encryptedData: encryptedData,
signature: signature,
timestamp: Date.now()
};

return payload;
}

// 서버로 전송
async function transmitData(payload) {
try {
var response = await fetch('/api/secure-endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload)
});

if (response.ok) {
console.log('안전한 데이터 전송 완료');
return await response.json();
} else {
throw new Error('전송 실패');
}
} catch (error) {
console.error('데이터 전송 오류:', error);
throw error;
}
}

// 사용 예제 (실제 서버 공개키 필요)
var sensitiveData = {
userId: 12345,
personalInfo: '민감한 개인정보',
financialData: { account: '123-456-789', balance: 1000000 }
};

// var serverPublicKey = '-----BEGIN PUBLIC KEY-----...';
// var securePayload = await sendSecureData(sensitiveData, serverPublicKey);
// await transmitData(securePayload);
}

// secureDataTransmission();

3. 클라이언트 측 데이터 보호

function clientDataProtection() {
// 민감한 설정 암호화 저장
function saveSecureSetting(key, value) {
var deviceFingerprint = syn.$b.fingerPrint();
var encryptedValue = syn.$c.encrypt(JSON.stringify(value), deviceFingerprint);
localStorage.setItem('secure_' + key, encryptedValue);
}

// 암호화된 설정 로드
function loadSecureSetting(key) {
var deviceFingerprint = syn.$b.fingerPrint();
var encryptedValue = localStorage.getItem('secure_' + key);

if (!encryptedValue) return null;

try {
var decryptedValue = syn.$c.decrypt(encryptedValue, deviceFingerprint);
return JSON.parse(decryptedValue);
} catch (error) {
console.warn('보안 설정 로드 실패 - 디바이스 변경 감지');
return null;
}
}

// 자동 로그아웃 타이머
function setupAutoLogout() {
var loginTime = Date.now();
var sessionDuration = 30 * 60 * 1000; // 30분

setInterval(() => {
var currentTime = Date.now();
if (currentTime - loginTime > sessionDuration) {
console.log('세션 만료 - 자동 로그아웃');
sessionStorage.clear();
localStorage.removeItem('sessionToken');
// 로그인 페이지로 리다이렉트
window.location.href = '/login';
}
}, 60000); // 1분마다 확인
}

// 사용 예제
saveSecureSetting('userPreferences', {
theme: 'dark',
language: 'ko-KR',
notifications: true
});

var preferences = loadSecureSetting('userPreferences');
console.log('로드된 설정:', preferences);

setupAutoLogout();
}

clientDataProtection();

4. 파일 무결성 검증

async function fileIntegrityCheck() {
// 파일 해시 계산
async function calculateFileHash(file) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.onload = async function(e) {
try {
var content = e.target.result;
var hash = await syn.$c.sha(content, 'SHA-256');
resolve(hash);
} catch (error) {
reject(error);
}
};
reader.onerror = reject;
reader.readAsText(file);
});
}

// 파일 업로드 시 무결성 확인
async function uploadWithIntegrity(file, expectedHash) {
console.log('파일 무결성 검사 시작...');

var calculatedHash = await calculateFileHash(file);

if (expectedHash && calculatedHash !== expectedHash) {
throw new Error('파일 무결성 검증 실패');
}

console.log('파일 해시:', calculatedHash);

// FormData 생성
var formData = new FormData();
formData.append('file', file);
formData.append('hash', calculatedHash);
formData.append('timestamp', Date.now().toString());

// HMAC 서명 추가
var signature = await syn.$c.generateHMAC('upload-key', calculatedHash);
formData.append('signature', signature);

return formData;
}

// 파일 입력 요소에 이벤트 등록
var fileInput = syn.$l.get('fileUpload');
if (fileInput) {
syn.$l.addEvent(fileInput, 'change', async function(e) {
var files = e.target.files;

for (var file of files) {
try {
var formData = await uploadWithIntegrity(file);
console.log('파일 준비 완료:', file.name);

// 실제 업로드
// await fetch('/api/upload', { method: 'POST', body: formData });

} catch (error) {
console.error('파일 처리 오류:', error);
}
}
});
}
}

fileIntegrityCheck();

주의사항

  1. 키 관리: 암호화 키는 절대 클라이언트 코드에 하드코딩하지 마세요. 환경변수나 안전한 키 관리 시스템을 사용하세요.
  2. 브라우저 지원: Web Crypto API는 HTTPS에서만 동작하며, 구형 브라우저에서는 지원되지 않을 수 있습니다.
  3. 성능 고려: 대용량 데이터의 암호화/복호화는 시간이 오래 걸릴 수 있습니다.
  4. 보안 강도: 중요한 데이터는 서버 측에서 추가적인 암호화를 적용하는 것이 좋습니다.
  5. 랜덤성: 암호화에 사용되는 초기화 벡터(IV)나 솔트는 반드시 안전한 랜덤 값을 사용해야 합니다.

관련 문서

데모

Javascript 예제

'use strict';
let $cryptography = {
extends: [
'parsehtml'
],

event: {
btn_base64Encode_click() {
syn.$l.get('txt_base64EncodeResult').value = syn.$c.base64Encode(syn.$l.get('txt_base64Encode').value);
},

btn_base64Decode_click() {
syn.$l.get('txt_base64DecodeResult').value = syn.$c.base64Decode(syn.$l.get('txt_base64Decode').value);
},

btn_utf8Encode_click() {
syn.$l.get('txt_utf8EncodeResult').value = syn.$c.utf8Encode(syn.$l.get('txt_utf8Encode').value);
},

btn_utf8Decode_click() {
syn.$l.get('txt_utf8DecodeResult').value = syn.$c.utf8Decode(syn.$l.get('txt_utf8Decode').value);
},

btn_sha256_click() {
syn.$l.get('txt_sha256Result').value = syn.$c.sha256(syn.$l.get('txt_sha256').value);
},

btn_encrypt_click() {
syn.$l.get('txt_encryptResult').value = syn.$c.encrypt(syn.$l.get('txt_encrypt').value);
},

btn_decrypt_click() {
syn.$l.get('txt_decryptResult').value = syn.$c.decrypt(syn.$l.get('txt_decrypt').value);
},

btn_LZStringEncode_click() {
syn.$l.get('txt_LZStringResult').value = syn.$c.LZString.compressToBase64(syn.$l.get('txt_LZString').value);
},

btn_LZStringDecode_click() {
syn.$l.get('txt_LZStringResult').value = syn.$c.LZString.decompressFromBase64(syn.$l.get('txt_LZString').value);
},
}
};

소스) syn.$c Javascript 예제