apk_sign_ts
v1.0.1
Published
Browser and Node APK signing library supporting JAR v1, APK Signature Scheme v2 and v3.
Maintainers
Readme
apk_sign_ts
A pure-TypeScript APK signing library that works in both Node.js and the browser. It supports the three main Android signing mechanisms:
- JAR v1 (
MANIFEST.MF,CERT.SF,CERT.RSA) - APK Signature Scheme v2
- APK Signature Scheme v3
Signed APKs are verified by Android's apksigner tool.
Features
- No backend required — all signing happens locally in the browser or Node process
- Loads keys from PEM strings or Java JKS keystores
- Produces v1 + v2 + v3 signatures in a single call
- Works with
crypto.subtlein browsers andcrypto.webcryptoin Node
Installation
npm install apk_sign_tsNode.js usage
Sign with PEM files
import { readFileSync, writeFileSync } from 'node:fs';
import { ApkSigner, SigningKey } from 'apk_sign_ts';
const apk = new Uint8Array(readFileSync('app.apk'));
const privateKey = readFileSync('my.key.pem', 'utf8');
const certificate = readFileSync('my.cert.pem', 'utf8');
const signer = new ApkSigner({
signingKey: SigningKey.fromPEM(privateKey, certificate)
});
const { signedApk } = await signer.sign(apk);
writeFileSync('app-signed.apk', signedApk);Sign with a Java KeyStore (JKS)
import { readFileSync } from 'node:fs';
import { ApkSigner, SigningKey, convertToPEM } from 'apk_sign_ts';
const apk = new Uint8Array(readFileSync('app.apk'));
const keystore = new Uint8Array(readFileSync('my.keystore'));
const { privateKey, certificate } = await convertToPEM(keystore, 'password', 'jks');
const signer = new ApkSigner({
signingKey: SigningKey.fromPEM(privateKey, certificate)
});
const { signedApk } = await signer.sign(apk);Verify the result
Use Android's apksigner from the build-tools:
apksigner verify --verbose --print-certs app-signed.apkExpected output:
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): trueBrowser / Vite usage
For bundlers, import from the browser-safe entry. It does not pull in jks-js.
import { ApkSigner, SigningKey } from 'apk_sign_ts';
const file = await fetch('my.key.pem').then(r => r.text());
const cert = await fetch('my.cert.pem').then(r => r.text());
const signer = new ApkSigner({
signingKey: SigningKey.fromPEM(file, cert)
});
const apk = new Uint8Array(await apkFile.arrayBuffer());
const { signedApk } = await signer.sign(apk);When using Vite, tell the resolver to prefer the browser field:
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
mainFields: ['browser', 'module', 'main']
}
});API
ApkSigner
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| signingKey | SigningKey | — | Key and certificate to sign with |
| digestAlgorithm | 'SHA-256' \| 'SHA-512' | 'SHA-512' | Digest used for v2/v3 |
| additionalAttributes | Map<number, Uint8Array> | new Map() | Extra v2 attributes |
| jarKeyName | string | 'CERT' | Prefix for v1 META-INF files |
const signer = new ApkSigner({ signingKey });
const { signedApk, signatureSize } = await signer.sign(apkData);SigningKey
const key = SigningKey.fromPEM(privateKeyPem, certificatePem);convertToPEM(keystoreData, password, format)
Extracts a private key and certificate from a Java keystore.
import { convertToPEM } from 'apk_sign_ts';
const { privateKey, certificate } = await convertToPEM(
new Uint8Array(keystoreFile),
'keystore-password',
'jks' // or 'pkcs12'
);