1
0
Fork 0
mirror of https://github.com/CorentinTh/it-tools.git synced 2025-08-09 07:25:18 +02:00

feat(new tool): rsa/ecdsa signing and verify

Fix #1084
This commit is contained in:
sharevb 2024-05-18 15:05:02 +02:00 committed by ShareVB
parent e876d03608
commit 2de5935fb7
7 changed files with 889 additions and 94 deletions

8
components.d.ts vendored
View file

@ -126,25 +126,26 @@ declare module '@vue/runtime-core' {
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default'] MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
NCode: typeof import('naive-ui')['NCode'] NCode: typeof import('naive-ui')['NCode']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NColorPicker: typeof import('naive-ui')['NColorPicker']
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDivider: typeof import('naive-ui')['NDivider']
NEllipsis: typeof import('naive-ui')['NEllipsis'] NEllipsis: typeof import('naive-ui')['NEllipsis']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem'] NFormItem: typeof import('naive-ui')['NFormItem']
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1'] NH1: typeof import('naive-ui')['NH1']
NH3: typeof import('naive-ui')['NH3'] NH3: typeof import('naive-ui')['NH3']
NIcon: typeof import('naive-ui')['NIcon'] NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
NInputNumber: typeof import('naive-ui')['NInputNumber'] NInputNumber: typeof import('naive-ui')['NInputNumber']
NLabel: typeof import('naive-ui')['NLabel']
NLayout: typeof import('naive-ui')['NLayout'] NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu'] NMenu: typeof import('naive-ui')['NMenu']
NScrollbar: typeof import('naive-ui')['NScrollbar'] NScrollbar: typeof import('naive-ui')['NScrollbar']
NSpin: typeof import('naive-ui')['NSpin']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
@ -158,6 +159,7 @@ declare module '@vue/runtime-core' {
RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default'] RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
RsaEcdsaSigning: typeof import('./src/tools/rsa-ecdsa-signing/rsa-ecdsa-signing.vue')['default']
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.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'] SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default']
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']

View file

@ -42,6 +42,7 @@
"@tiptap/starter-kit": "2.1.6", "@tiptap/starter-kit": "2.1.6",
"@tiptap/vue-3": "2.0.3", "@tiptap/vue-3": "2.0.3",
"@types/figlet": "^1.5.8", "@types/figlet": "^1.5.8",
"@types/sshpk": "^1.17.4",
"@vicons/material": "^0.12.0", "@vicons/material": "^0.12.0",
"@vicons/tabler": "^0.12.0", "@vicons/tabler": "^0.12.0",
"@vueuse/core": "^10.3.0", "@vueuse/core": "^10.3.0",
@ -81,11 +82,13 @@
"plausible-tracker": "^0.3.8", "plausible-tracker": "^0.3.8",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"sql-formatter": "^13.0.0", "sql-formatter": "^13.0.0",
"sshpk": "^1.18.0",
"ua-parser-js": "^1.0.35", "ua-parser-js": "^1.0.35",
"ulid": "^2.3.0", "ulid": "^2.3.0",
"unicode-emoji-json": "^0.4.0", "unicode-emoji-json": "^0.4.0",
"unplugin-auto-import": "^0.16.4", "unplugin-auto-import": "^0.16.4",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"vite-plugin-node-polyfills": "^0.21.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-i18n": "^9.9.1", "vue-i18n": "^9.9.1",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",

802
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter'; import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as rsaEcdsaSigning } from './rsa-ecdsa-signing';
import { tool as asciiTextDrawer } from './ascii-text-drawer'; import { tool as asciiTextDrawer } from './ascii-text-drawer';
@ -85,7 +86,21 @@ import { tool as yamlViewer } from './yaml-viewer';
export const toolsByCategory: ToolCategory[] = [ export const toolsByCategory: ToolCategory[] = [
{ {
name: 'Crypto', 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,
// pgpEncryption,
rsaEcdsaSigning,
],
}, },
{ {
name: 'Converter', name: 'Converter',

View file

@ -0,0 +1,12 @@
import { Lock } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'RSA/DSA/ECDSA Signer and Verifier',
path: '/rsa-ecdsa-signing',
description: 'Sign data and verify signature using RSA/DSA/ECDSA Keys',
keywords: ['rsa', 'dsa', 'ecdsa', 'ed25519', 'encryption', 'cypher', 'encipher', 'crypt', 'decrypt'],
component: () => import('./rsa-ecdsa-signing.vue'),
icon: Lock,
createdAt: new Date('2024-05-01'),
});

View file

@ -0,0 +1,139 @@
<script setup lang="ts">
import sshpk from 'sshpk';
import { computedCatch } from '@/composable/computed/catchedComputed';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
const hashTypes = [
'sha1', 'sha256', 'sha384', 'sha512', 'md5',
];
const verifyText = ref('');
const verifySignature = ref('');
const verifyPublicKey = ref('');
const [verifyOutput, verifyError] = computedCatch(() => {
const publicKey = sshpk.parseKey(verifyPublicKey.value, 'auto');
const v = publicKey.createVerify();
v.update(verifyText.value);
return v.verify(verifySignature.value);
}, {
defaultValue: '',
defaultErrorMessage: 'Unable to verify your text',
});
const signText = ref('');
const signPrivateKey = ref('');
const signPrivateKeyPassphrase = ref('');
const signHashType = ref('sha1');
const [signOutput, signError] = computedCatch(() => {
const privateKey = sshpk.parsePrivateKey(signPrivateKey.value, 'auto', { passphrase: signPrivateKeyPassphrase.value });
const s = privateKey.createSign(signHashType.value as sshpk.AlgorithmHashType);
s.update(signText.value);
const signature = s.sign();
return {
asn1: signature.toString('asn1'),
ssh: signature.toString('ssh'),
};
}, {
defaultValue: {
asn1: '',
ssh: '',
},
defaultErrorMessage: 'Unable to sign your text',
});
</script>
<template>
<div>
<c-card title="Sign">
<div>
<c-input-text
v-model:value="signText"
label="Your text:"
placeholder="The string to sign"
rows="4"
multiline raw-text monospace autosize flex-1
/>
<c-select
v-model:value="signHashType"
label="Hash Type:"
:options="hashTypes"
placeholder="Select the hashing algorithm"
/>
<div flex flex-1 flex-col gap-2>
<c-input-text
v-model:value="signPrivateKey"
label="Your private key:"
placeholder="The private key to use to sign message"
rows="5"
multiline raw-text monospace autosize flex-1
/>
<c-input-text
v-model:value="signPrivateKeyPassphrase"
label="Your private key password:" clearable raw-text
/>
</div>
</div>
<c-alert v-if="signError && signPrivateKey !== ''" type="error" mt-12 title="Error while signing">
{{ signError }}
</c-alert>
<n-form-item label="ASN1 Signature:" mt-3>
<TextareaCopyable
:value="signOutput?.asn1 || ''"
placeholder="ASN1 Signature"
multiline monospace readonly autosize mt-5
/>
</n-form-item>
<n-form-item label="SSH Signature:" mt-3>
<TextareaCopyable
:value="signOutput?.ssh || ''"
placeholder="SSG Signature"
multiline monospace readonly autosize mt-5
/>
</n-form-item>
</c-card>
<c-card title="Verify">
<div>
<c-input-text
v-model:value="verifyText"
label="Your text to verify:"
placeholder="The string to verify"
rows="4"
multiline raw-text monospace autosize flex-1
/>
<c-input-text
v-model:value="verifySignature"
label="Associated signature:"
placeholder="Text signature"
rows="4"
multiline raw-text monospace autosize flex-1
/>
<div flex flex-1 flex-col gap-2>
<c-input-text
v-model:value="verifyPublicKey"
label="Public key:"
placeholder="Public key"
rows="5"
multiline raw-text monospace autosize flex-1
/>
</div>
</div>
<c-alert v-if="verifyError && verifyPublicKey !== ''" type="error" mt-12 title="Error while verifying">
{{ verifyError }}
</c-alert>
<c-alert v-if="verifyOutput && verifyPublicKey !== ''" type="error" mt-12 title="Signature failed">
Signature is NOT valid for the given text
</c-alert>
<n-alert v-if="!verifyOutput && verifyPublicKey !== ''" type="success" mt-12 title="Signature verified">
Signature is valid for the given text
</n-alert>
</c-card>
</div>
</template>

View file

@ -1,5 +1,6 @@
import { resolve } from 'node:path'; import { resolve } from 'node:path';
import { URL, fileURLToPath } from 'node:url'; import { URL, fileURLToPath } from 'node:url';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import VueI18n from '@intlify/unplugin-vue-i18n/vite'; import VueI18n from '@intlify/unplugin-vue-i18n/vite';
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
@ -97,6 +98,7 @@ export default defineConfig({
resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })], resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })],
}), }),
Unocss(), Unocss(),
nodePolyfills(),
], ],
base: baseUrl, base: baseUrl,
resolve: { resolve: {