@twin.org/crypto 0.0.1 → 0.0.2-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@ var blake2b = require('@noble/hashes/blake2b');
8
8
  var bip32 = require('@scure/bip32');
9
9
  var slip10_js = require('micro-key-producer/slip10.js');
10
10
  var chacha = require('@noble/ciphers/chacha');
11
+ var node_crypto = require('node:crypto');
11
12
  var blake3 = require('@noble/hashes/blake3');
12
13
  var hmac = require('@noble/hashes/hmac');
13
14
  var sha1 = require('@noble/hashes/sha1');
@@ -717,8 +718,215 @@ class ChaCha20Poly1305 {
717
718
  // Copyright 2024 IOTA Stiftung.
718
719
  // SPDX-License-Identifier: Apache-2.0.
719
720
  /**
720
- * This is a TypeScript port of https://github.com/katzenpost/core/blob/master/crypto/extra25519/extra25519.go.
721
+ * Implementation of the RSA cipher.
721
722
  */
723
+ class RSA {
724
+ /**
725
+ * Runtime name for the class.
726
+ * @internal
727
+ */
728
+ static _CLASS_NAME = "RSA";
729
+ /**
730
+ * The public key for encryption.
731
+ * @internal
732
+ */
733
+ _publicKey;
734
+ /**
735
+ * The private key for decryption.
736
+ * @internal
737
+ */
738
+ _privateKey;
739
+ /**
740
+ * The block size for encryption.
741
+ * @internal
742
+ */
743
+ _blockSize;
744
+ /**
745
+ * The key size for decryption.
746
+ * @internal
747
+ */
748
+ _keySize;
749
+ /**
750
+ * Create a new instance of RSA.
751
+ * @param publicKey The public key for encryption (DER format as Uint8Array).
752
+ * @param privateKey The private key for decryption (DER format as Uint8Array).
753
+ */
754
+ constructor(publicKey, privateKey) {
755
+ core.Guards.uint8Array(RSA._CLASS_NAME, "publicKey", publicKey);
756
+ this._publicKey = node_crypto.createPublicKey({
757
+ key: Buffer.from(publicKey),
758
+ format: "der",
759
+ type: "spki"
760
+ });
761
+ if (!core.Is.empty(privateKey)) {
762
+ this._privateKey = node_crypto.createPrivateKey({
763
+ key: Buffer.from(privateKey),
764
+ format: "der",
765
+ type: "pkcs8"
766
+ });
767
+ }
768
+ // Get modulus length in bits from key details
769
+ const modulusLengthBits = this._publicKey.asymmetricKeyDetails?.modulusLength;
770
+ if (core.Is.empty(modulusLengthBits)) {
771
+ throw new core.GeneralError(RSA._CLASS_NAME, "invalidKeySize");
772
+ }
773
+ // Convert bits to bytes
774
+ this._keySize = Math.ceil(modulusLengthBits / 8);
775
+ // Calculate block size for OAEP with SHA-256
776
+ // Formula: keySize - 2 * hashLength - 2
777
+ const hashLength = 32; // SHA-256 = 32 bytes
778
+ // eslint-disable-next-line no-mixed-operators
779
+ this._blockSize = this._keySize - 2 * hashLength - 2;
780
+ }
781
+ /**
782
+ * Generate a new RSA key pair in PKCS8 format.
783
+ * @param modulusLength The key size in bits (default: 2048).
784
+ * @returns The public and private keys as Uint8Array.
785
+ */
786
+ static generateKeyPair(modulusLength = 2048) {
787
+ const { publicKey, privateKey } = node_crypto.generateKeyPairSync("rsa", {
788
+ modulusLength,
789
+ publicKeyEncoding: {
790
+ type: "spki",
791
+ format: "der"
792
+ },
793
+ privateKeyEncoding: {
794
+ type: "pkcs8",
795
+ format: "der"
796
+ }
797
+ });
798
+ return {
799
+ publicKey: new Uint8Array(publicKey),
800
+ privateKey: new Uint8Array(privateKey)
801
+ };
802
+ }
803
+ /**
804
+ * Convert a PKCS1 key to a PKCS8 key.
805
+ * @param pkcs1Key The PKCS1 key as Uint8Array.
806
+ * @returns The PKCS8 key as Uint8Array.
807
+ */
808
+ static convertPkcs1ToPkcs8(pkcs1Key) {
809
+ core.Guards.uint8Array(RSA._CLASS_NAME, "pkcs1Key", pkcs1Key);
810
+ const privateKey = node_crypto.createPrivateKey({
811
+ key: Buffer.from(pkcs1Key),
812
+ format: "der",
813
+ type: "pkcs1"
814
+ });
815
+ return new Uint8Array(privateKey.export({
816
+ format: "der",
817
+ type: "pkcs8"
818
+ }));
819
+ }
820
+ /**
821
+ * Break the private key down in to its components.
822
+ * @param pkcs8Key The PKCS8 key as Uint8Array.
823
+ * @returns The key components.
824
+ */
825
+ static getPrivateKeyComponents(pkcs8Key) {
826
+ core.Guards.uint8Array(RSA._CLASS_NAME, "pkcs8Key", pkcs8Key);
827
+ const privateKey = node_crypto.createPrivateKey({
828
+ key: Buffer.from(pkcs8Key),
829
+ format: "der",
830
+ type: "pkcs8"
831
+ });
832
+ const jwk = privateKey.export({ format: "jwk" });
833
+ return {
834
+ n: this.base64UrlToBigInt(jwk.n),
835
+ e: this.base64UrlToBigInt(jwk.e),
836
+ d: this.base64UrlToBigInt(jwk.d),
837
+ p: this.base64UrlToBigInt(jwk.p),
838
+ q: this.base64UrlToBigInt(jwk.q),
839
+ dp: this.base64UrlToBigInt(jwk.dp),
840
+ dq: this.base64UrlToBigInt(jwk.dq),
841
+ qi: this.base64UrlToBigInt(jwk.qi)
842
+ };
843
+ }
844
+ /**
845
+ * Break the public key down in to its components.
846
+ * @param spkiKey The SPKI key as Uint8Array.
847
+ * @returns The key components.
848
+ */
849
+ static getPublicKeyComponents(spkiKey) {
850
+ core.Guards.uint8Array(RSA._CLASS_NAME, "spkiKey", spkiKey);
851
+ const publicKey = node_crypto.createPublicKey({
852
+ key: Buffer.from(spkiKey),
853
+ format: "der",
854
+ type: "spki"
855
+ });
856
+ const jwk = publicKey.export({ format: "jwk" });
857
+ return {
858
+ n: this.base64UrlToBigInt(jwk.n),
859
+ e: this.base64UrlToBigInt(jwk.e)
860
+ };
861
+ }
862
+ /**
863
+ * Convert base64 encoded data to a big int.
864
+ * @param bytes The bytes to convert.
865
+ * @returns The bigint representation of the bytes.
866
+ * @internal
867
+ */
868
+ static base64UrlToBigInt(base64Url) {
869
+ if (core.Is.empty(base64Url)) {
870
+ return BigInt(0);
871
+ }
872
+ const bytes = core.Converter.base64UrlToBytes(base64Url);
873
+ const hexString = Array.from(bytes)
874
+ .map(byte => byte.toString(16).padStart(2, "0"))
875
+ .join("");
876
+ return BigInt(`0x${hexString}`);
877
+ }
878
+ /**
879
+ * Encrypt the data.
880
+ * @param data The data to encrypt.
881
+ * @returns The data encrypted.
882
+ */
883
+ encrypt(data) {
884
+ core.Guards.uint8Array(RSA._CLASS_NAME, "data", data);
885
+ if (data.length === 0) {
886
+ return new Uint8Array(0);
887
+ }
888
+ const blocks = [];
889
+ // Split data into blocks of block size
890
+ for (let i = 0; i < data.length; i += this._blockSize) {
891
+ const block = data.slice(i, i + this._blockSize);
892
+ const encryptedBlock = node_crypto.publicEncrypt({
893
+ key: this._publicKey,
894
+ padding: node_crypto.constants.RSA_PKCS1_OAEP_PADDING
895
+ }, block);
896
+ blocks.push(encryptedBlock);
897
+ }
898
+ return core.Uint8ArrayHelper.concat(blocks);
899
+ }
900
+ /**
901
+ * Decrypt the data.
902
+ * @param data The data to decrypt.
903
+ * @returns The data decrypted.
904
+ * @throws GeneralError If no private key is provided.
905
+ */
906
+ decrypt(data) {
907
+ core.Guards.uint8Array(RSA._CLASS_NAME, "data", data);
908
+ if (core.Is.empty(this._privateKey)) {
909
+ throw new core.GeneralError(RSA._CLASS_NAME, "noPrivateKey");
910
+ }
911
+ if (data.length === 0) {
912
+ return new Uint8Array(0);
913
+ }
914
+ const blocks = [];
915
+ // Split encrypted data into blocks of key size
916
+ for (let i = 0; i < data.length; i += this._keySize) {
917
+ const block = data.slice(i, i + this._keySize);
918
+ const decryptedBlock = node_crypto.privateDecrypt({
919
+ key: this._privateKey,
920
+ padding: node_crypto.constants.RSA_PKCS1_OAEP_PADDING
921
+ }, block);
922
+ blocks.push(decryptedBlock);
923
+ }
924
+ return core.Uint8ArrayHelper.concat(blocks);
925
+ }
926
+ }
927
+
928
+ // Copyright 2024 IOTA Stiftung.
929
+ // SPDX-License-Identifier: Apache-2.0.
722
930
  /**
723
931
  * Implementation of X25519.
724
932
  */
@@ -1526,6 +1734,48 @@ class Sha512 {
1526
1734
  }
1527
1735
  }
1528
1736
 
1737
+ // Copyright 2024 IOTA Stiftung.
1738
+ // SPDX-License-Identifier: Apache-2.0.
1739
+ /**
1740
+ * Helper class for working with PEM (Privacy-Enhanced Mail) formatted data.
1741
+ */
1742
+ class PemHelper {
1743
+ /**
1744
+ * Runtime name for the class.
1745
+ * @internal
1746
+ */
1747
+ static _CLASS_NAME = "PemHelper";
1748
+ /**
1749
+ * Strip the PEM content of its headers, footers, and newlines.
1750
+ * @param pemContent The PEM content to strip.
1751
+ * @returns The stripped PEM content in bas64 format.
1752
+ */
1753
+ static stripPemMarkers(pemContent) {
1754
+ core.Guards.string(PemHelper._CLASS_NAME, "pemContent", pemContent);
1755
+ return pemContent
1756
+ .replace(/-----BEGIN.*-----/, "")
1757
+ .replace(/-----END.*-----/, "")
1758
+ .replace(/\n/g, "")
1759
+ .trim();
1760
+ }
1761
+ /**
1762
+ * Format the PEM content to have a specific line length.
1763
+ * @param marker The marker for the PEM content, e.g. RSA PRIVATE KEY
1764
+ * @param base64Content The base64 content to format.
1765
+ * @param lineLength The length of each line in the PEM content, default is 64 characters.
1766
+ * @returns The formatted PEM content.
1767
+ */
1768
+ static formatPem(marker, base64Content, lineLength = 64) {
1769
+ core.Guards.stringValue(PemHelper._CLASS_NAME, "marker", marker);
1770
+ core.Guards.stringBase64(PemHelper._CLASS_NAME, "base64Content", base64Content);
1771
+ const lines = [];
1772
+ for (let i = 0; i < base64Content.length; i += lineLength) {
1773
+ lines.push(base64Content.slice(i, i + lineLength));
1774
+ }
1775
+ return [`-----BEGIN ${marker}-----`, ...lines, `-----END ${marker}-----`].join("\n");
1776
+ }
1777
+ }
1778
+
1529
1779
  // Copyright 2024 IOTA Stiftung.
1530
1780
  // SPDX-License-Identifier: Apache-2.0.
1531
1781
  /**
@@ -1812,6 +2062,8 @@ exports.KeyType = KeyType;
1812
2062
  exports.PasswordGenerator = PasswordGenerator;
1813
2063
  exports.PasswordValidator = PasswordValidator;
1814
2064
  exports.Pbkdf2 = Pbkdf2;
2065
+ exports.PemHelper = PemHelper;
2066
+ exports.RSA = RSA;
1815
2067
  exports.Secp256k1 = Secp256k1;
1816
2068
  exports.Sha1 = Sha1;
1817
2069
  exports.Sha256 = Sha256;
@@ -6,6 +6,7 @@ import { blake2b } from '@noble/hashes/blake2b';
6
6
  import { HDKey as HDKey$1 } from '@scure/bip32';
7
7
  import { HDKey } from 'micro-key-producer/slip10.js';
8
8
  import { chacha20poly1305 } from '@noble/ciphers/chacha';
9
+ import { createPublicKey, createPrivateKey, generateKeyPairSync, publicEncrypt, constants, privateDecrypt } from 'node:crypto';
9
10
  import { blake3 } from '@noble/hashes/blake3';
10
11
  import { hmac } from '@noble/hashes/hmac';
11
12
  import { sha1 } from '@noble/hashes/sha1';
@@ -695,8 +696,215 @@ class ChaCha20Poly1305 {
695
696
  // Copyright 2024 IOTA Stiftung.
696
697
  // SPDX-License-Identifier: Apache-2.0.
697
698
  /**
698
- * This is a TypeScript port of https://github.com/katzenpost/core/blob/master/crypto/extra25519/extra25519.go.
699
+ * Implementation of the RSA cipher.
699
700
  */
701
+ class RSA {
702
+ /**
703
+ * Runtime name for the class.
704
+ * @internal
705
+ */
706
+ static _CLASS_NAME = "RSA";
707
+ /**
708
+ * The public key for encryption.
709
+ * @internal
710
+ */
711
+ _publicKey;
712
+ /**
713
+ * The private key for decryption.
714
+ * @internal
715
+ */
716
+ _privateKey;
717
+ /**
718
+ * The block size for encryption.
719
+ * @internal
720
+ */
721
+ _blockSize;
722
+ /**
723
+ * The key size for decryption.
724
+ * @internal
725
+ */
726
+ _keySize;
727
+ /**
728
+ * Create a new instance of RSA.
729
+ * @param publicKey The public key for encryption (DER format as Uint8Array).
730
+ * @param privateKey The private key for decryption (DER format as Uint8Array).
731
+ */
732
+ constructor(publicKey, privateKey) {
733
+ Guards.uint8Array(RSA._CLASS_NAME, "publicKey", publicKey);
734
+ this._publicKey = createPublicKey({
735
+ key: Buffer.from(publicKey),
736
+ format: "der",
737
+ type: "spki"
738
+ });
739
+ if (!Is.empty(privateKey)) {
740
+ this._privateKey = createPrivateKey({
741
+ key: Buffer.from(privateKey),
742
+ format: "der",
743
+ type: "pkcs8"
744
+ });
745
+ }
746
+ // Get modulus length in bits from key details
747
+ const modulusLengthBits = this._publicKey.asymmetricKeyDetails?.modulusLength;
748
+ if (Is.empty(modulusLengthBits)) {
749
+ throw new GeneralError(RSA._CLASS_NAME, "invalidKeySize");
750
+ }
751
+ // Convert bits to bytes
752
+ this._keySize = Math.ceil(modulusLengthBits / 8);
753
+ // Calculate block size for OAEP with SHA-256
754
+ // Formula: keySize - 2 * hashLength - 2
755
+ const hashLength = 32; // SHA-256 = 32 bytes
756
+ // eslint-disable-next-line no-mixed-operators
757
+ this._blockSize = this._keySize - 2 * hashLength - 2;
758
+ }
759
+ /**
760
+ * Generate a new RSA key pair in PKCS8 format.
761
+ * @param modulusLength The key size in bits (default: 2048).
762
+ * @returns The public and private keys as Uint8Array.
763
+ */
764
+ static generateKeyPair(modulusLength = 2048) {
765
+ const { publicKey, privateKey } = generateKeyPairSync("rsa", {
766
+ modulusLength,
767
+ publicKeyEncoding: {
768
+ type: "spki",
769
+ format: "der"
770
+ },
771
+ privateKeyEncoding: {
772
+ type: "pkcs8",
773
+ format: "der"
774
+ }
775
+ });
776
+ return {
777
+ publicKey: new Uint8Array(publicKey),
778
+ privateKey: new Uint8Array(privateKey)
779
+ };
780
+ }
781
+ /**
782
+ * Convert a PKCS1 key to a PKCS8 key.
783
+ * @param pkcs1Key The PKCS1 key as Uint8Array.
784
+ * @returns The PKCS8 key as Uint8Array.
785
+ */
786
+ static convertPkcs1ToPkcs8(pkcs1Key) {
787
+ Guards.uint8Array(RSA._CLASS_NAME, "pkcs1Key", pkcs1Key);
788
+ const privateKey = createPrivateKey({
789
+ key: Buffer.from(pkcs1Key),
790
+ format: "der",
791
+ type: "pkcs1"
792
+ });
793
+ return new Uint8Array(privateKey.export({
794
+ format: "der",
795
+ type: "pkcs8"
796
+ }));
797
+ }
798
+ /**
799
+ * Break the private key down in to its components.
800
+ * @param pkcs8Key The PKCS8 key as Uint8Array.
801
+ * @returns The key components.
802
+ */
803
+ static getPrivateKeyComponents(pkcs8Key) {
804
+ Guards.uint8Array(RSA._CLASS_NAME, "pkcs8Key", pkcs8Key);
805
+ const privateKey = createPrivateKey({
806
+ key: Buffer.from(pkcs8Key),
807
+ format: "der",
808
+ type: "pkcs8"
809
+ });
810
+ const jwk = privateKey.export({ format: "jwk" });
811
+ return {
812
+ n: this.base64UrlToBigInt(jwk.n),
813
+ e: this.base64UrlToBigInt(jwk.e),
814
+ d: this.base64UrlToBigInt(jwk.d),
815
+ p: this.base64UrlToBigInt(jwk.p),
816
+ q: this.base64UrlToBigInt(jwk.q),
817
+ dp: this.base64UrlToBigInt(jwk.dp),
818
+ dq: this.base64UrlToBigInt(jwk.dq),
819
+ qi: this.base64UrlToBigInt(jwk.qi)
820
+ };
821
+ }
822
+ /**
823
+ * Break the public key down in to its components.
824
+ * @param spkiKey The SPKI key as Uint8Array.
825
+ * @returns The key components.
826
+ */
827
+ static getPublicKeyComponents(spkiKey) {
828
+ Guards.uint8Array(RSA._CLASS_NAME, "spkiKey", spkiKey);
829
+ const publicKey = createPublicKey({
830
+ key: Buffer.from(spkiKey),
831
+ format: "der",
832
+ type: "spki"
833
+ });
834
+ const jwk = publicKey.export({ format: "jwk" });
835
+ return {
836
+ n: this.base64UrlToBigInt(jwk.n),
837
+ e: this.base64UrlToBigInt(jwk.e)
838
+ };
839
+ }
840
+ /**
841
+ * Convert base64 encoded data to a big int.
842
+ * @param bytes The bytes to convert.
843
+ * @returns The bigint representation of the bytes.
844
+ * @internal
845
+ */
846
+ static base64UrlToBigInt(base64Url) {
847
+ if (Is.empty(base64Url)) {
848
+ return BigInt(0);
849
+ }
850
+ const bytes = Converter.base64UrlToBytes(base64Url);
851
+ const hexString = Array.from(bytes)
852
+ .map(byte => byte.toString(16).padStart(2, "0"))
853
+ .join("");
854
+ return BigInt(`0x${hexString}`);
855
+ }
856
+ /**
857
+ * Encrypt the data.
858
+ * @param data The data to encrypt.
859
+ * @returns The data encrypted.
860
+ */
861
+ encrypt(data) {
862
+ Guards.uint8Array(RSA._CLASS_NAME, "data", data);
863
+ if (data.length === 0) {
864
+ return new Uint8Array(0);
865
+ }
866
+ const blocks = [];
867
+ // Split data into blocks of block size
868
+ for (let i = 0; i < data.length; i += this._blockSize) {
869
+ const block = data.slice(i, i + this._blockSize);
870
+ const encryptedBlock = publicEncrypt({
871
+ key: this._publicKey,
872
+ padding: constants.RSA_PKCS1_OAEP_PADDING
873
+ }, block);
874
+ blocks.push(encryptedBlock);
875
+ }
876
+ return Uint8ArrayHelper.concat(blocks);
877
+ }
878
+ /**
879
+ * Decrypt the data.
880
+ * @param data The data to decrypt.
881
+ * @returns The data decrypted.
882
+ * @throws GeneralError If no private key is provided.
883
+ */
884
+ decrypt(data) {
885
+ Guards.uint8Array(RSA._CLASS_NAME, "data", data);
886
+ if (Is.empty(this._privateKey)) {
887
+ throw new GeneralError(RSA._CLASS_NAME, "noPrivateKey");
888
+ }
889
+ if (data.length === 0) {
890
+ return new Uint8Array(0);
891
+ }
892
+ const blocks = [];
893
+ // Split encrypted data into blocks of key size
894
+ for (let i = 0; i < data.length; i += this._keySize) {
895
+ const block = data.slice(i, i + this._keySize);
896
+ const decryptedBlock = privateDecrypt({
897
+ key: this._privateKey,
898
+ padding: constants.RSA_PKCS1_OAEP_PADDING
899
+ }, block);
900
+ blocks.push(decryptedBlock);
901
+ }
902
+ return Uint8ArrayHelper.concat(blocks);
903
+ }
904
+ }
905
+
906
+ // Copyright 2024 IOTA Stiftung.
907
+ // SPDX-License-Identifier: Apache-2.0.
700
908
  /**
701
909
  * Implementation of X25519.
702
910
  */
@@ -1504,6 +1712,48 @@ class Sha512 {
1504
1712
  }
1505
1713
  }
1506
1714
 
1715
+ // Copyright 2024 IOTA Stiftung.
1716
+ // SPDX-License-Identifier: Apache-2.0.
1717
+ /**
1718
+ * Helper class for working with PEM (Privacy-Enhanced Mail) formatted data.
1719
+ */
1720
+ class PemHelper {
1721
+ /**
1722
+ * Runtime name for the class.
1723
+ * @internal
1724
+ */
1725
+ static _CLASS_NAME = "PemHelper";
1726
+ /**
1727
+ * Strip the PEM content of its headers, footers, and newlines.
1728
+ * @param pemContent The PEM content to strip.
1729
+ * @returns The stripped PEM content in bas64 format.
1730
+ */
1731
+ static stripPemMarkers(pemContent) {
1732
+ Guards.string(PemHelper._CLASS_NAME, "pemContent", pemContent);
1733
+ return pemContent
1734
+ .replace(/-----BEGIN.*-----/, "")
1735
+ .replace(/-----END.*-----/, "")
1736
+ .replace(/\n/g, "")
1737
+ .trim();
1738
+ }
1739
+ /**
1740
+ * Format the PEM content to have a specific line length.
1741
+ * @param marker The marker for the PEM content, e.g. RSA PRIVATE KEY
1742
+ * @param base64Content The base64 content to format.
1743
+ * @param lineLength The length of each line in the PEM content, default is 64 characters.
1744
+ * @returns The formatted PEM content.
1745
+ */
1746
+ static formatPem(marker, base64Content, lineLength = 64) {
1747
+ Guards.stringValue(PemHelper._CLASS_NAME, "marker", marker);
1748
+ Guards.stringBase64(PemHelper._CLASS_NAME, "base64Content", base64Content);
1749
+ const lines = [];
1750
+ for (let i = 0; i < base64Content.length; i += lineLength) {
1751
+ lines.push(base64Content.slice(i, i + lineLength));
1752
+ }
1753
+ return [`-----BEGIN ${marker}-----`, ...lines, `-----END ${marker}-----`].join("\n");
1754
+ }
1755
+ }
1756
+
1507
1757
  // Copyright 2024 IOTA Stiftung.
1508
1758
  // SPDX-License-Identifier: Apache-2.0.
1509
1759
  /**
@@ -1774,4 +2024,4 @@ class PasswordValidator {
1774
2024
  }
1775
2025
  }
1776
2026
 
1777
- export { Bech32, Bip32Path, Bip39, Bip44, Blake2b, Blake3, ChaCha20Poly1305, Ed25519, HmacSha1, HmacSha256, HmacSha512, Hotp, KeyType, PasswordGenerator, PasswordValidator, Pbkdf2, Secp256k1, Sha1, Sha256, Sha3, Sha512, Slip0010, Totp, X25519, Zip215 };
2027
+ export { Bech32, Bip32Path, Bip39, Bip44, Blake2b, Blake3, ChaCha20Poly1305, Ed25519, HmacSha1, HmacSha256, HmacSha512, Hotp, KeyType, PasswordGenerator, PasswordValidator, Pbkdf2, PemHelper, RSA, Secp256k1, Sha1, Sha256, Sha3, Sha512, Slip0010, Totp, X25519, Zip215 };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Implementation of the RSA cipher.
3
+ */
4
+ export declare class RSA {
5
+ /**
6
+ * Create a new instance of RSA.
7
+ * @param publicKey The public key for encryption (DER format as Uint8Array).
8
+ * @param privateKey The private key for decryption (DER format as Uint8Array).
9
+ */
10
+ constructor(publicKey: Uint8Array, privateKey?: Uint8Array);
11
+ /**
12
+ * Generate a new RSA key pair in PKCS8 format.
13
+ * @param modulusLength The key size in bits (default: 2048).
14
+ * @returns The public and private keys as Uint8Array.
15
+ */
16
+ static generateKeyPair(modulusLength?: number): {
17
+ publicKey: Uint8Array;
18
+ privateKey: Uint8Array;
19
+ };
20
+ /**
21
+ * Convert a PKCS1 key to a PKCS8 key.
22
+ * @param pkcs1Key The PKCS1 key as Uint8Array.
23
+ * @returns The PKCS8 key as Uint8Array.
24
+ */
25
+ static convertPkcs1ToPkcs8(pkcs1Key: Uint8Array): Uint8Array;
26
+ /**
27
+ * Break the private key down in to its components.
28
+ * @param pkcs8Key The PKCS8 key as Uint8Array.
29
+ * @returns The key components.
30
+ */
31
+ static getPrivateKeyComponents(pkcs8Key: Uint8Array): {
32
+ n: bigint;
33
+ e: bigint;
34
+ d: bigint;
35
+ p: bigint;
36
+ q: bigint;
37
+ dp: bigint;
38
+ dq: bigint;
39
+ qi: bigint;
40
+ };
41
+ /**
42
+ * Break the public key down in to its components.
43
+ * @param spkiKey The SPKI key as Uint8Array.
44
+ * @returns The key components.
45
+ */
46
+ static getPublicKeyComponents(spkiKey: Uint8Array): {
47
+ n: bigint;
48
+ e: bigint;
49
+ };
50
+ /**
51
+ * Encrypt the data.
52
+ * @param data The data to encrypt.
53
+ * @returns The data encrypted.
54
+ */
55
+ encrypt(data: Uint8Array): Uint8Array;
56
+ /**
57
+ * Decrypt the data.
58
+ * @param data The data to decrypt.
59
+ * @returns The data decrypted.
60
+ * @throws GeneralError If no private key is provided.
61
+ */
62
+ decrypt(data: Uint8Array): Uint8Array;
63
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Helper class for working with PEM (Privacy-Enhanced Mail) formatted data.
3
+ */
4
+ export declare class PemHelper {
5
+ /**
6
+ * Strip the PEM content of its headers, footers, and newlines.
7
+ * @param pemContent The PEM content to strip.
8
+ * @returns The stripped PEM content in bas64 format.
9
+ */
10
+ static stripPemMarkers(pemContent: string): string;
11
+ /**
12
+ * Format the PEM content to have a specific line length.
13
+ * @param marker The marker for the PEM content, e.g. RSA PRIVATE KEY
14
+ * @param base64Content The base64 content to format.
15
+ * @param lineLength The length of each line in the PEM content, default is 64 characters.
16
+ * @returns The formatted PEM content.
17
+ */
18
+ static formatPem(marker: string, base64Content: string, lineLength?: number): string;
19
+ }
@@ -1,6 +1,7 @@
1
1
  export * from "./address/bech32";
2
2
  export * from "./address/bip44";
3
3
  export * from "./ciphers/chaCha20Poly1305";
4
+ export * from "./ciphers/rsa";
4
5
  export * from "./curves/ed25519";
5
6
  export * from "./curves/secp256k1";
6
7
  export * from "./curves/x25519";
@@ -15,6 +16,7 @@ export * from "./hashes/sha1";
15
16
  export * from "./hashes/sha256";
16
17
  export * from "./hashes/sha3";
17
18
  export * from "./hashes/sha512";
19
+ export * from "./helpers/pemHelper";
18
20
  export * from "./keys/bip32Path";
19
21
  export * from "./keys/bip39";
20
22
  export * from "./keys/slip0010";
package/docs/changelog.md CHANGED
@@ -1,5 +1,74 @@
1
1
  # @twin.org/crypto - Changelog
2
2
 
3
+ ## [0.0.2-next.3](https://github.com/twinfoundation/framework/compare/crypto-v0.0.2-next.2...crypto-v0.0.2-next.3) (2025-08-06)
4
+
5
+
6
+ ### Features
7
+
8
+ * add guards arrayEndsWith and arrayStartsWith ([95d875e](https://github.com/twinfoundation/framework/commit/95d875ec8ccb4713c145fdde941d4cfedcec2ed3))
9
+ * add rsa cipher support ([7af6cc6](https://github.com/twinfoundation/framework/commit/7af6cc67512d3363bd4a2f2e87bd7733c2800147))
10
+ * add RSA support for public key components ([7126259](https://github.com/twinfoundation/framework/commit/7126259103b758c291e52a8a03818eb822d1aad1))
11
+ * change method accessibility ([c1b77fc](https://github.com/twinfoundation/framework/commit/c1b77fcfb61c092a01c97aebb2fe2dc2bbaa221b))
12
+ * relocate core packages from tools ([bcab8f3](https://github.com/twinfoundation/framework/commit/bcab8f3160442ea4fcaf442947462504f3d6a17d))
13
+ * update dependencies ([f3bd015](https://github.com/twinfoundation/framework/commit/f3bd015efd169196b7e0335f5cab876ba6ca1d75))
14
+ * use new shared store mechanism ([#131](https://github.com/twinfoundation/framework/issues/131)) ([934385b](https://github.com/twinfoundation/framework/commit/934385b2fbaf9f5c00a505ebf9d093bd5a425f55))
15
+
16
+
17
+ ### Dependencies
18
+
19
+ * The following workspace dependencies were updated
20
+ * dependencies
21
+ * @twin.org/core bumped from 0.0.2-next.2 to 0.0.2-next.3
22
+ * @twin.org/nameof bumped from 0.0.2-next.2 to 0.0.2-next.3
23
+ * devDependencies
24
+ * @twin.org/nameof-transformer bumped from 0.0.2-next.2 to 0.0.2-next.3
25
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.2-next.2 to 0.0.2-next.3
26
+
27
+ ## [0.0.2-next.2](https://github.com/twinfoundation/framework/compare/crypto-v0.0.2-next.1...crypto-v0.0.2-next.2) (2025-08-06)
28
+
29
+
30
+ ### Features
31
+
32
+ * add guards arrayEndsWith and arrayStartsWith ([95d875e](https://github.com/twinfoundation/framework/commit/95d875ec8ccb4713c145fdde941d4cfedcec2ed3))
33
+ * add rsa cipher support ([7af6cc6](https://github.com/twinfoundation/framework/commit/7af6cc67512d3363bd4a2f2e87bd7733c2800147))
34
+ * change method accessibility ([c1b77fc](https://github.com/twinfoundation/framework/commit/c1b77fcfb61c092a01c97aebb2fe2dc2bbaa221b))
35
+ * relocate core packages from tools ([bcab8f3](https://github.com/twinfoundation/framework/commit/bcab8f3160442ea4fcaf442947462504f3d6a17d))
36
+ * update dependencies ([f3bd015](https://github.com/twinfoundation/framework/commit/f3bd015efd169196b7e0335f5cab876ba6ca1d75))
37
+ * use new shared store mechanism ([#131](https://github.com/twinfoundation/framework/issues/131)) ([934385b](https://github.com/twinfoundation/framework/commit/934385b2fbaf9f5c00a505ebf9d093bd5a425f55))
38
+
39
+
40
+ ### Dependencies
41
+
42
+ * The following workspace dependencies were updated
43
+ * dependencies
44
+ * @twin.org/core bumped from 0.0.2-next.1 to 0.0.2-next.2
45
+ * @twin.org/nameof bumped from 0.0.2-next.1 to 0.0.2-next.2
46
+ * devDependencies
47
+ * @twin.org/nameof-transformer bumped from 0.0.2-next.1 to 0.0.2-next.2
48
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.2-next.1 to 0.0.2-next.2
49
+
50
+ ## [0.0.2-next.1](https://github.com/twinfoundation/framework/compare/crypto-v0.0.2-next.0...crypto-v0.0.2-next.1) (2025-08-06)
51
+
52
+
53
+ ### Features
54
+
55
+ * add guards arrayEndsWith and arrayStartsWith ([95d875e](https://github.com/twinfoundation/framework/commit/95d875ec8ccb4713c145fdde941d4cfedcec2ed3))
56
+ * add rsa cipher support ([7af6cc6](https://github.com/twinfoundation/framework/commit/7af6cc67512d3363bd4a2f2e87bd7733c2800147))
57
+ * relocate core packages from tools ([bcab8f3](https://github.com/twinfoundation/framework/commit/bcab8f3160442ea4fcaf442947462504f3d6a17d))
58
+ * update dependencies ([f3bd015](https://github.com/twinfoundation/framework/commit/f3bd015efd169196b7e0335f5cab876ba6ca1d75))
59
+ * use new shared store mechanism ([#131](https://github.com/twinfoundation/framework/issues/131)) ([934385b](https://github.com/twinfoundation/framework/commit/934385b2fbaf9f5c00a505ebf9d093bd5a425f55))
60
+
61
+
62
+ ### Dependencies
63
+
64
+ * The following workspace dependencies were updated
65
+ * dependencies
66
+ * @twin.org/core bumped from 0.0.2-next.0 to 0.0.2-next.1
67
+ * @twin.org/nameof bumped from 0.0.2-next.0 to 0.0.2-next.1
68
+ * devDependencies
69
+ * @twin.org/nameof-transformer bumped from 0.0.2-next.0 to 0.0.2-next.1
70
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.2-next.0 to 0.0.2-next.1
71
+
3
72
  ## 0.0.1 (2025-07-03)
4
73
 
5
74
 
@@ -0,0 +1,69 @@
1
+ # Class: PemHelper
2
+
3
+ Helper class for working with PEM (Privacy-Enhanced Mail) formatted data.
4
+
5
+ ## Constructors
6
+
7
+ ### Constructor
8
+
9
+ > **new PemHelper**(): `PemHelper`
10
+
11
+ #### Returns
12
+
13
+ `PemHelper`
14
+
15
+ ## Methods
16
+
17
+ ### stripPemMarkers()
18
+
19
+ > `static` **stripPemMarkers**(`pemContent`): `string`
20
+
21
+ Strip the PEM content of its headers, footers, and newlines.
22
+
23
+ #### Parameters
24
+
25
+ ##### pemContent
26
+
27
+ `string`
28
+
29
+ The PEM content to strip.
30
+
31
+ #### Returns
32
+
33
+ `string`
34
+
35
+ The stripped PEM content in bas64 format.
36
+
37
+ ***
38
+
39
+ ### formatPem()
40
+
41
+ > `static` **formatPem**(`marker`, `base64Content`, `lineLength`): `string`
42
+
43
+ Format the PEM content to have a specific line length.
44
+
45
+ #### Parameters
46
+
47
+ ##### marker
48
+
49
+ `string`
50
+
51
+ The marker for the PEM content, e.g. RSA PRIVATE KEY
52
+
53
+ ##### base64Content
54
+
55
+ `string`
56
+
57
+ The base64 content to format.
58
+
59
+ ##### lineLength
60
+
61
+ `number` = `64`
62
+
63
+ The length of each line in the PEM content, default is 64 characters.
64
+
65
+ #### Returns
66
+
67
+ `string`
68
+
69
+ The formatted PEM content.
@@ -0,0 +1,213 @@
1
+ # Class: RSA
2
+
3
+ Implementation of the RSA cipher.
4
+
5
+ ## Constructors
6
+
7
+ ### Constructor
8
+
9
+ > **new RSA**(`publicKey`, `privateKey?`): `RSA`
10
+
11
+ Create a new instance of RSA.
12
+
13
+ #### Parameters
14
+
15
+ ##### publicKey
16
+
17
+ `Uint8Array`
18
+
19
+ The public key for encryption (DER format as Uint8Array).
20
+
21
+ ##### privateKey?
22
+
23
+ `Uint8Array`\<`ArrayBufferLike`\>
24
+
25
+ The private key for decryption (DER format as Uint8Array).
26
+
27
+ #### Returns
28
+
29
+ `RSA`
30
+
31
+ ## Methods
32
+
33
+ ### generateKeyPair()
34
+
35
+ > `static` **generateKeyPair**(`modulusLength`): `object`
36
+
37
+ Generate a new RSA key pair in PKCS8 format.
38
+
39
+ #### Parameters
40
+
41
+ ##### modulusLength
42
+
43
+ `number` = `2048`
44
+
45
+ The key size in bits (default: 2048).
46
+
47
+ #### Returns
48
+
49
+ `object`
50
+
51
+ The public and private keys as Uint8Array.
52
+
53
+ ##### publicKey
54
+
55
+ > **publicKey**: `Uint8Array`
56
+
57
+ ##### privateKey
58
+
59
+ > **privateKey**: `Uint8Array`
60
+
61
+ ***
62
+
63
+ ### convertPkcs1ToPkcs8()
64
+
65
+ > `static` **convertPkcs1ToPkcs8**(`pkcs1Key`): `Uint8Array`
66
+
67
+ Convert a PKCS1 key to a PKCS8 key.
68
+
69
+ #### Parameters
70
+
71
+ ##### pkcs1Key
72
+
73
+ `Uint8Array`
74
+
75
+ The PKCS1 key as Uint8Array.
76
+
77
+ #### Returns
78
+
79
+ `Uint8Array`
80
+
81
+ The PKCS8 key as Uint8Array.
82
+
83
+ ***
84
+
85
+ ### getPrivateKeyComponents()
86
+
87
+ > `static` **getPrivateKeyComponents**(`pkcs8Key`): `object`
88
+
89
+ Break the private key down in to its components.
90
+
91
+ #### Parameters
92
+
93
+ ##### pkcs8Key
94
+
95
+ `Uint8Array`
96
+
97
+ The PKCS8 key as Uint8Array.
98
+
99
+ #### Returns
100
+
101
+ `object`
102
+
103
+ The key components.
104
+
105
+ ##### n
106
+
107
+ > **n**: `bigint`
108
+
109
+ ##### e
110
+
111
+ > **e**: `bigint`
112
+
113
+ ##### d
114
+
115
+ > **d**: `bigint`
116
+
117
+ ##### p
118
+
119
+ > **p**: `bigint`
120
+
121
+ ##### q
122
+
123
+ > **q**: `bigint`
124
+
125
+ ##### dp
126
+
127
+ > **dp**: `bigint`
128
+
129
+ ##### dq
130
+
131
+ > **dq**: `bigint`
132
+
133
+ ##### qi
134
+
135
+ > **qi**: `bigint`
136
+
137
+ ***
138
+
139
+ ### getPublicKeyComponents()
140
+
141
+ > `static` **getPublicKeyComponents**(`spkiKey`): `object`
142
+
143
+ Break the public key down in to its components.
144
+
145
+ #### Parameters
146
+
147
+ ##### spkiKey
148
+
149
+ `Uint8Array`
150
+
151
+ The SPKI key as Uint8Array.
152
+
153
+ #### Returns
154
+
155
+ `object`
156
+
157
+ The key components.
158
+
159
+ ##### n
160
+
161
+ > **n**: `bigint`
162
+
163
+ ##### e
164
+
165
+ > **e**: `bigint`
166
+
167
+ ***
168
+
169
+ ### encrypt()
170
+
171
+ > **encrypt**(`data`): `Uint8Array`
172
+
173
+ Encrypt the data.
174
+
175
+ #### Parameters
176
+
177
+ ##### data
178
+
179
+ `Uint8Array`
180
+
181
+ The data to encrypt.
182
+
183
+ #### Returns
184
+
185
+ `Uint8Array`
186
+
187
+ The data encrypted.
188
+
189
+ ***
190
+
191
+ ### decrypt()
192
+
193
+ > **decrypt**(`data`): `Uint8Array`
194
+
195
+ Decrypt the data.
196
+
197
+ #### Parameters
198
+
199
+ ##### data
200
+
201
+ `Uint8Array`
202
+
203
+ The data to decrypt.
204
+
205
+ #### Returns
206
+
207
+ `Uint8Array`
208
+
209
+ The data decrypted.
210
+
211
+ #### Throws
212
+
213
+ GeneralError If no private key is provided.
@@ -5,6 +5,7 @@
5
5
  - [Bech32](classes/Bech32.md)
6
6
  - [Bip44](classes/Bip44.md)
7
7
  - [ChaCha20Poly1305](classes/ChaCha20Poly1305.md)
8
+ - [RSA](classes/RSA.md)
8
9
  - [Ed25519](classes/Ed25519.md)
9
10
  - [Secp256k1](classes/Secp256k1.md)
10
11
  - [X25519](classes/X25519.md)
@@ -19,6 +20,7 @@
19
20
  - [Sha256](classes/Sha256.md)
20
21
  - [Sha3](classes/Sha3.md)
21
22
  - [Sha512](classes/Sha512.md)
23
+ - [PemHelper](classes/PemHelper.md)
22
24
  - [Bip32Path](classes/Bip32Path.md)
23
25
  - [Bip39](classes/Bip39.md)
24
26
  - [Slip0010](classes/Slip0010.md)
package/locales/en.json CHANGED
@@ -63,6 +63,10 @@
63
63
  },
64
64
  "slip0010": {
65
65
  "invalidSeed": "The seed is invalid \"{seed}\""
66
+ },
67
+ "rsa": {
68
+ "noPrivateKey": "Private key is required for decryption",
69
+ "invalidKeySize": "Invalid RSA key size"
66
70
  }
67
71
  }
68
72
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/crypto",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-next.3",
4
4
  "description": "Contains helper methods and classes which implement cryptographic functions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,8 +20,8 @@
20
20
  "@scure/base": "1.2.6",
21
21
  "@scure/bip32": "1.7.0",
22
22
  "@scure/bip39": "1.6.0",
23
- "@twin.org/core": "^0.0.1",
24
- "@twin.org/nameof": "^0.0.1",
23
+ "@twin.org/core": "0.0.2-next.3",
24
+ "@twin.org/nameof": "0.0.2-next.3",
25
25
  "micro-key-producer": "0.7.6"
26
26
  },
27
27
  "main": "./dist/cjs/index.cjs",