From ca44c5c52a5134418f00a39363b7804908b22df2 Mon Sep 17 00:00:00 2001 From: sharevb Date: Sat, 17 Feb 2024 17:23:16 +0100 Subject: [PATCH] feat(new tool): Ed25519 Key Pair Generator Fix #281 (ed25519 key pairs, passphrase and openssh format) Supports generation in PEM, PKCS#8, OpenSSH Standard (with or without passphrase), OpenSSH (new format) and PuTTY (no passphrase) --- components.d.ts | 47 +---------- .../ed25519-key-pair-generator.service.ts | 30 +++++++ .../ed25519-key-pair-generator.vue | 80 +++++++++++++++++++ src/tools/ed25519-key-pair-generator/index.ts | 12 +++ src/tools/index.ts | 16 +++- 5 files changed, 138 insertions(+), 47 deletions(-) create mode 100644 src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.service.ts create mode 100644 src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.vue create mode 100644 src/tools/ed25519-key-pair-generator/index.ts diff --git a/components.d.ts b/components.d.ts index fabbe793..e77f48ec 100644 --- a/components.d.ts +++ b/components.d.ts @@ -70,6 +70,7 @@ declare module '@vue/runtime-core' { DiffViewer: typeof import('./src/tools/json-diff/diff-viewer/diff-viewer.vue')['default'] DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default'] DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default'] + Ed25519KeyPairGenerator: typeof import('./src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.vue')['default'] Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default'] EmojiCard: typeof import('./src/tools/emoji-picker/emoji-card.vue')['default'] EmojiGrid: typeof import('./src/tools/emoji-picker/emoji-grid.vue')['default'] @@ -88,28 +89,9 @@ declare module '@vue/runtime-core' { HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default'] IbanValidatorAndParser: typeof import('./src/tools/iban-validator-and-parser/iban-validator-and-parser.vue')['default'] 'IconMdi:brushVariant': typeof import('~icons/mdi/brush-variant')['default'] - 'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default'] 'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default'] - IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default'] - IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default'] - IconMdiCamera: typeof import('~icons/mdi/camera')['default'] - IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] - IconMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] - IconMdiClose: typeof import('~icons/mdi/close')['default'] IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] - IconMdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default'] - IconMdiDownload: typeof import('~icons/mdi/download')['default'] - IconMdiEye: typeof import('~icons/mdi/eye')['default'] - IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default'] - IconMdiHeart: typeof import('~icons/mdi/heart')['default'] - IconMdiPause: typeof import('~icons/mdi/pause')['default'] - IconMdiPlay: typeof import('~icons/mdi/play')['default'] - IconMdiRecord: typeof import('~icons/mdi/record')['default'] - IconMdiRefresh: typeof import('~icons/mdi/refresh')['default'] - IconMdiSearch: typeof import('~icons/mdi/search')['default'] IconMdiTranslate: typeof import('~icons/mdi/translate')['default'] - IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default'] - IconMdiVideo: typeof import('~icons/mdi/video')['default'] InputCopyable: typeof import('./src/components/InputCopyable.vue')['default'] IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default'] Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] @@ -136,39 +118,12 @@ declare module '@vue/runtime-core' { MenuLayout: typeof import('./src/components/MenuLayout.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'] - NAlert: typeof import('naive-ui')['NAlert'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] - NCheckbox: typeof import('naive-ui')['NCheckbox'] - NCode: typeof import('naive-ui')['NCode'] - NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] - NColorPicker: typeof import('naive-ui')['NColorPicker'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] - NDatePicker: typeof import('naive-ui')['NDatePicker'] - NDivider: typeof import('naive-ui')['NDivider'] - NDynamicInput: typeof import('naive-ui')['NDynamicInput'] NEllipsis: typeof import('naive-ui')['NEllipsis'] - NForm: typeof import('naive-ui')['NForm'] - NFormItem: typeof import('naive-ui')['NFormItem'] - NGi: typeof import('naive-ui')['NGi'] - NGrid: typeof import('naive-ui')['NGrid'] NH1: typeof import('naive-ui')['NH1'] - NH2: typeof import('naive-ui')['NH2'] NH3: typeof import('naive-ui')['NH3'] NIcon: typeof import('naive-ui')['NIcon'] - NImage: typeof import('naive-ui')['NImage'] - NInputGroup: typeof import('naive-ui')['NInputGroup'] - NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel'] - NInputNumber: typeof import('naive-ui')['NInputNumber'] - NLayout: typeof import('naive-ui')['NLayout'] - NLayoutSider: typeof import('naive-ui')['NLayoutSider'] - NMenu: typeof import('naive-ui')['NMenu'] - NProgress: typeof import('naive-ui')['NProgress'] - NScrollbar: typeof import('naive-ui')['NScrollbar'] - NSlider: typeof import('naive-ui')['NSlider'] - NStatistic: typeof import('naive-ui')['NStatistic'] - NSwitch: typeof import('naive-ui')['NSwitch'] - NTable: typeof import('naive-ui')['NTable'] - NTag: typeof import('naive-ui')['NTag'] 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'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] diff --git a/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.service.ts b/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.service.ts new file mode 100644 index 00000000..f07a015a --- /dev/null +++ b/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.service.ts @@ -0,0 +1,30 @@ +import sshpk from 'sshpk'; + +export { generateKeyPair }; + +async function generateKeyPair(config: { + password?: string + format?: sshpk.PrivateKeyFormatType + comment?: string +} = {}) { + const privKey = sshpk.generatePrivateKey('ed25519'); + privKey.comment = config?.comment; + + const pubFormat = config.format ?? 'ssh'; + let privFormat: sshpk.PrivateKeyFormatType = config.format ?? 'ssh'; + if (privFormat === 'ssh') { + privFormat = 'ssh-private'; + } + const pubKey = privKey.toPublic(); + return { + publicKey: pubKey.toString(pubFormat), + privateKey: config?.password + ? privKey.toString(privFormat, + { + passphrase: config?.password, + comment: config?.comment, + }, + ) + : privKey.toString(privFormat, { comment: config?.comment }), + }; +} diff --git a/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.vue b/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.vue new file mode 100644 index 00000000..e4514524 --- /dev/null +++ b/src/tools/ed25519-key-pair-generator/ed25519-key-pair-generator.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/tools/ed25519-key-pair-generator/index.ts b/src/tools/ed25519-key-pair-generator/index.ts new file mode 100644 index 00000000..63cc0ba3 --- /dev/null +++ b/src/tools/ed25519-key-pair-generator/index.ts @@ -0,0 +1,12 @@ +import { Certificate } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Ed25519 key pair generator', + path: '/ed25519-key-pair-generator', + description: 'Generate new random Ed25519 private and public keys (with or without passphrase).', + keywords: ['ed25519', 'key', 'pair', 'generator', 'public', 'private', 'secret', 'ssh', 'pem', 'passphrase', 'password'], + component: () => import('./ed25519-key-pair-generator.vue'), + icon: Certificate, + createdAt: new Date('2024-02-14'), +}); diff --git a/src/tools/index.ts b/src/tools/index.ts index 2a477ed2..ed90ed8b 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64StringConverter } from './base64-string-converter'; import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as textToUnicode } from './text-to-unicode'; +import { tool as ed25519KeyPairGenerator } from './ed25519-key-pair-generator'; import { tool as pdfSignatureChecker } from './pdf-signature-checker'; import { tool as numeronymGenerator } from './numeronym-generator'; import { tool as macAddressGenerator } from './mac-address-generator'; @@ -81,7 +82,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, + ed25519KeyPairGenerator, + passwordStrengthAnalyser, + pdfSignatureChecker, + ], }, { name: 'Converter',