All files index.ts

97.72% Statements 43/44
66.66% Branches 6/9
100% Functions 8/8
97.61% Lines 41/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111104x                   1x 1x     1x 1x 1x 1x 1x     1x 8x 8x     1x 8x     1x 6x 6x 6x 6x     1x         2x 2x                     1x           2x 2x 2x 2x     1x           3x     3x 3x 3x 3x 3x 3x 3x                                 2x           2x 2x 2x 2x 2x    
import {
    Bytes,
    Checksum256,
    Checksum512,
    PrivateKey,
    PublicKey,
    Serializer,
    Struct,
    UInt32,
    UInt64,
} from '@wharfkit/antelope'
import {AES_CBC} from '@greymass/miniaes'
 
@Struct.type('sealed_message')
export class SealedMessage extends Struct {
    @Struct.field('public_key') from!: PublicKey
    @Struct.field('uint64') nonce!: UInt64
    @Struct.field('bytes') ciphertext!: Bytes
    @Struct.field('uint32') checksum!: UInt32
}
 
export function createSymmetricKey(secret: Checksum512, nonce: UInt64): Uint8Array {
    const key = Checksum512.hash(Serializer.encode({object: nonce}).appending(secret.array))
    return key.array.slice(0, 32)
}
 
export function createIV(nonce: UInt64, secret: Checksum512): Checksum512 {
    return Checksum512.hash(Serializer.encode({object: nonce}).appending(secret.array))
}
 
export function encryptMessage(iv: Checksum512, symmetricKey: Uint8Array, message: string): Bytes {
    const plaintext = Bytes.from(message, 'utf8').array
    const ivBytes = iv.array.slice(32, 48)
    const encrypted = AES_CBC.encrypt(plaintext, symmetricKey, true, ivBytes)
    return Bytes.from(encrypted)
}
 
export function decryptMessage(
    iv: Checksum512,
    symmetricKey: Uint8Array,
    message: Bytes
): Uint8Array {
    const ivBytes = iv.array.slice(32, 48)
    return AES_CBC.decrypt(message.array, symmetricKey, true, ivBytes)
}
 
/**
 * Seals a message using AES encryption and a shared secret derived from given keys.
 * @param message - The message to seal
 * @param privateKey - The private key to use for encryption
 * @param publicKey - The public key to use for encryption
 * @param nonce - A nonce to use for encryption
 * @returns The sealed message as Bytes
 */
export function sealMessage(
    message: string,
    privateKey: PrivateKey,
    publicKey: PublicKey,
    nonce: UInt64
): Bytes {
    const secret = privateKey.sharedSecret(publicKey, {legacy: true})
    const iv = createIV(nonce, secret)
    const symmetricKey = createSymmetricKey(secret, nonce)
    return encryptMessage(iv, symmetricKey, message)
}
 
export function sealedMessagePayload(
    message: string,
    privateKey: PrivateKey,
    publicKey: PublicKey,
    nonce?: UInt64
): SealedMessage {
    Iif (!nonce) {
        nonce = UInt64.random()
    }
    const secret = privateKey.sharedSecret(publicKey, {legacy: true})
    const iv = createIV(nonce, secret)
    const symmetricKey = createSymmetricKey(secret, nonce)
    const ciphertext = encryptMessage(iv, symmetricKey, message)
    const checksumView = new DataView(Checksum256.hash(iv.array).array.buffer)
    const checksum = checksumView.getUint32(0, true)
    return new SealedMessage({
        from: privateKey.toPublic(),
        nonce,
        ciphertext,
        checksum,
    })
}
 
/**
 * Decrypt a message using AES and shared secret derived from given keys.
 * @param message - The encrypted message bytes to decrypt
 * @param privateKey - The private key to use for deriving the shared secret
 * @param publicKey - The public key to use for deriving the shared secret
 * @param nonce - The nonce used in the encryption process
 * @returns The decrypted message as a UTF-8 string
 * @internal
 */
export function unsealMessage(
    message: Bytes,
    privateKey: PrivateKey,
    publicKey: PublicKey,
    nonce: UInt64
): string {
    const secret = privateKey.sharedSecret(publicKey, {legacy: true})
    const iv = createIV(nonce, secret)
    const symmetricKey = createSymmetricKey(secret, nonce)
    const decryptedMessage = decryptMessage(iv, symmetricKey, message)
    return Bytes.from(decryptedMessage).toString('utf8')
}