Skip to content

How it works

Mert Cobanov edited this page Jul 29, 2026 · 2 revisions

How it works

No RIM APIs

BlackBerry signing was a runtime check that fired when a module touched a protected API, and every signature came from an authority that no longer exists. Code touching no protected API needs no signature — so berryssh touches none, and the build needs no BlackBerry tooling at all.

The cost: no native UI framework. The screens are MIDP, drawn by the device in its own theme.

Modern crypto is the cheap option here

CLDC 1.1 has no java.security, no javax.crypto, no BigInteger, so every primitive is implemented in the project. The algorithm choice is what makes that tractable: curve25519 and ed25519 are fixed 32-byte field arithmetic, chacha20-poly1305 is add/xor/rotate with no tables and needs no separate MAC.

The 2011 SSH stack is anchored on 2048-bit modular exponentiation, genuinely slow in interpreted Java on this CPU. So the handset reaches a current OpenSSH by using the newer algorithms, not older ones.

Streams, not sockets

Connection takes an InputStream and an OutputStream and has never known where they came from.

That is why the protocol code is free of MIDP and can run on a desktop JVM against a real OpenSSH server — encodings can be proved with vectors, a protocol cannot. It is also why carrying SSH over a WebSocket cost almost nothing: a WebSocket-backed pair substitutes with no change above it.

Verification

Compiling at -source 1.3 against the CLDC bootclasspath proves it will run on the handset; executing on the host JVM proves it is correct. 228 offline vectors, plus 39 against a real server covering what vectors cannot — a negotiated key exchange, a pty, a shell, a rekey, typing while output arrives, and a bridge refusing a wrong key.

Everything runs under a Turkish default locale on purpose: "I".toLowerCase() is a dotless ı there, and protocol code that case-folds is broken in a way that raises no error.

Odds and ends

Random numbers. No SecureRandom, and java.util.Random is a 48-bit LCG seeded from the clock. EntropyPool harvests timing jitter into a SHA-256 DRBG, refuses to emit anything below 256 bits of state, and ratchets after every output.

The terminal. VT320 is ported from BBSSH and credited in the file. The rendering is not: MIDP's smallest font gives a 21×13 terminal on this screen, so berryssh draws from a bitmap atlas instead, which is what makes 60×25 possible.

Threads. Two, sharing a transport with separate locks per direction — one lock would mean every keystroke waiting on the network.

Storage. RMS, versioned, older layouts still read. UTF-8 throughout, because the device's default encoding is ISO8859_1 and would mangle a password with a Turkish letter in it.

Clone this wiki locally