Skip to content

Commit

Permalink
feat(new tool): RSA Encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
sharevb committed Apr 28, 2024
1 parent 9eac9cb commit 97a2a11
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 8 deletions.
2 changes: 2 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ declare module '@vue/runtime-core' {
RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
RsaEncryption: typeof import('./src/tools/rsa-encryption/rsa-encryption.vue')['default']
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default']
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"highlight.js": "^11.7.0",
"iarna-toml-esm": "^3.0.5",
"ibantools": "^4.3.3",
"js-base64": "^3.7.7",
"json5": "^2.2.3",
"jwt-decode": "^3.1.2",
"libphonenumber-js": "^1.10.28",
Expand Down
20 changes: 14 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion src/composable/computed/catchedComputed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type Ref, ref, watchEffect } from 'vue';

export { computedCatch };
export { computedCatch, computedCatchAsync };

function computedCatch<T, D>(getter: () => T, { defaultValue }: { defaultValue: D; defaultErrorMessage?: string }): [Ref<T | D>, Ref<string | undefined>];
function computedCatch<T, D>(getter: () => T, { defaultValue, defaultErrorMessage = 'Unknown error' }: { defaultValue?: D; defaultErrorMessage?: string } = {}) {
Expand All @@ -20,3 +20,22 @@ function computedCatch<T, D>(getter: () => T, { defaultValue, defaultErrorMessag

return [value, error] as const;
}

function computedCatchAsync<T, D>(getterAsync: () => Promise<T>, { defaultValue }: { defaultValue: D; defaultErrorMessage?: string }): [Ref<T | D>, Ref<string | undefined>];
function computedCatchAsync<T, D>(getterAsync: () => Promise<T>, { defaultValue, defaultErrorMessage = 'Unknown error' }: { defaultValue?: D; defaultErrorMessage?: string } = {}) {
const error = ref<string | undefined>();
const value = ref<T | D | undefined>();

watchEffect(async () => {
try {
error.value = undefined;
value.value = await getterAsync();
}
catch (err) {
error.value = err instanceof Error ? err.message : err?.toString() ?? defaultErrorMessage;
value.value = defaultValue;
}
});

return [value, error] as const;
}
16 changes: 15 additions & 1 deletion src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer';

import { tool as textToUnicode } from './text-to-unicode';
import { tool as safelinkDecoder } from './safelink-decoder';
import { tool as rsaEncryption } from './rsa-encryption';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
Expand Down Expand Up @@ -85,7 +86,20 @@ import { tool as yamlViewer } from './yaml-viewer';
export const toolsByCategory: ToolCategory[] = [
{
name: 'Crypto',
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker],
components: [
tokenGenerator,
hashText,
bcrypt,
uuidGenerator,
ulidGenerator,
cypher,
bip39,
hmacGenerator,
rsaKeyPairGenerator,
passwordStrengthAnalyser,
pdfSignatureChecker,
rsaEncryption,
],
},
{
name: 'Converter',
Expand Down
12 changes: 12 additions & 0 deletions src/tools/rsa-encryption/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Lock } from '@vicons/tabler';
import { defineTool } from '../tool';

export const tool = defineTool({
name: 'RSA encryption',
path: '/rsa-encryption',
description: 'Encrypt and decrypt text clear text using RSA Keys.',
keywords: ['rsa', 'encryption', 'cypher', 'encipher', 'crypt', 'decrypt'],
component: () => import('./rsa-encryption.vue'),
icon: Lock,
createdAt: new Date('2024-04-20'),
});
188 changes: 188 additions & 0 deletions src/tools/rsa-encryption/rsa-encryption.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<script setup lang="ts">
import { md, pki } from 'node-forge';
import { Base64 } from 'js-base64';
import { computedCatchAsync } from '@/composable/computed/catchedComputed';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
const schemes = [
{ value: 'RSAES-PKCS1-V1_5', label: 'RSAES PKCS#1 v1.5' },
{ value: 'RSAES-OAEP', label: 'RSAES-OAEP' },
{ value: 'RSAES-OAEP/SHA-256', label: 'RSAES-OAEP/SHA-256' },
{ value: 'RSAES-OAEP/SHA-256/MGF1-SHA-1', label: 'RSAES-OAEP/SHA-256/MGF1-SHA-1 (RSA/ECB/OAEPWithSHA-256AndMGF1Padding)' },
];
const cryptInput = ref('');
const cryptScheme = ref('RSAES-PKCS1-V1_5');
const cryptPublicKey = ref('');
const [cryptOutput, cryptError] = computedCatchAsync(async () => {
const publicKeyPEM = cryptPublicKey.value;
const text = cryptInput.value;
const scheme = cryptScheme.value;
const publicKey = pki.publicKeyFromPem(publicKeyPEM);
let encrypted;
if (scheme === 'RSAES-PKCS1-V1_5') {
// encrypt data with a public key using RSAES PKCS#1 v1.5
encrypted = publicKey.encrypt(text, 'RSAES-PKCS1-V1_5');
}
else if (scheme === 'RSAES-OAEP') {
// encrypt data with a public key using RSAES-OAEP
encrypted = publicKey.encrypt(text, 'RSA-OAEP');
}
else if (scheme === 'RSAES-OAEP/SHA-256') {
// encrypt data with a public key using RSAES-OAEP/SHA-256
encrypted = publicKey.encrypt(text, 'RSA-OAEP', {
md: md.sha256.create(),
});
}
else if (scheme === 'RSAES-OAEP/SHA-256/MGF1-SHA-1') {
// encrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1
// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
encrypted = publicKey.encrypt(text, 'RSA-OAEP', {
md: md.sha256.create(),
mgf1: {
md: md.sha1.create(),
},
});
}
return Base64.encode(encrypted || '');
}, {
defaultValue: '',
defaultErrorMessage: 'Unable to encrypt your text',
});
const decryptInput = ref('');
const decryptScheme = ref('RSAES-PKCS1-V1_5');
const decryptPrivateKey = ref('');
const decryptPrivateKeyPassphrase = ref('');
const [decryptOutput, decryptError] = computedCatchAsync(async () => {
const privateKeyPEM = decryptPrivateKey.value;
const passphrase = decryptPrivateKeyPassphrase.value;
const encrypted = Base64.decode(decryptInput.value);
const scheme = decryptScheme.value;
const privateKey = pki.decryptRsaPrivateKey(privateKeyPEM, passphrase);
let decrypted;
if (scheme === 'RSAES-PKCS1-V1_5') {
// decrypt data with a private key using RSAES PKCS#1 v1.5
decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5');
}
else if (scheme === 'RSAES-OAEP') {
// decrypt data with a private key using RSAES-OAEP
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP');
}
else if (scheme === 'RSAES-OAEP/SHA-256') {
// decrypt data with a private key using RSAES-OAEP/SHA-256
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
md: md.sha256.create(),
});
}
else if (scheme === 'RSAES-OAEP/SHA-256/MGF1-SHA-1') {
// decrypt data with a private key using RSAES-OAEP/SHA-256/MGF1-SHA-1
// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
md: md.sha256.create(),
mgf1: {
md: md.sha1.create(),
},
});
}
return decrypted;
}, {
defaultValue: '',
defaultErrorMessage: 'Unable to encrypt your text',
});
</script>

<template>
<div>
<c-card title="Encrypt">
<div>
<c-input-text
v-model:value="cryptInput"
label="Your text:"
placeholder="The string to encrypt"
rows="4"
multiline raw-text monospace autosize flex-1
/>
<c-select
v-model:value="cryptScheme"
label="Scheme:"
:options="schemes"
placeholder="Select the encryption scheme"
/>
<div flex flex-1 flex-col gap-2>
<c-input-text
v-model:value="cryptPublicKey"
label="Target public key:"
placeholder="Target public key"
rows="5"
multiline raw-text monospace autosize flex-1
/>
</div>
</div>

<c-alert v-if="cryptError && cryptPublicKey !== ''" type="error" mt-12 title="Error while encrypting">
{{ cryptError }}
</c-alert>

<n-form-item label="Your text encrypted:" mt-3>
<TextareaCopyable
:value="cryptOutput || ''"
rows="3"
placeholder="Your string encrypted"
multiline monospace readonly autosize mt-5
/>
</n-form-item>
</c-card>

<c-card title="Decrypt">
<div>
<c-input-text
v-model:value="decryptInput"
label="Your PGP Message to decrypt:"
placeholder="The string to decrypt"
rows="4"
multiline raw-text monospace autosize flex-1
/>

<c-select
v-model:value="decryptScheme"
label="Scheme:"
:options="schemes"
placeholder="Select the encryption scheme"
/>

<div flex flex-1 flex-col gap-2>
<c-input-text
v-model:value="decryptPrivateKey"
label="Your private key:"
placeholder="The private key to use to decrypt message"
rows="5"
multiline raw-text monospace autosize flex-1
/>

<c-input-text
v-model:value="decryptPrivateKeyPassphrase"
label="Your private key password:" clearable raw-text
/>
</div>
</div>

<c-alert v-if="decryptError && decryptPrivateKey !== ''" type="error" mt-12 title="Error while decrypting">
{{ decryptError }}
</c-alert>

<n-form-item label="Your text decrypted:" mt-3>
<TextareaCopyable
:value="decryptOutput || ''"
rows="3"
placeholder="Your string decrypted"
multiline monospace readonly autosize mt-5
/>
</n-form-item>
</c-card>
</div>
</template>

0 comments on commit 97a2a11

Please sign in to comment.