pspssh changelog
v2.1.1 · Jul 31, 2026
- Put back the wait that was holding the picture together (#64)
v2.0.0 · Jul 31, 2026
An SSH client for the PlayStation Portable that talks to a current OpenSSH server — and, as of this release, one you never need a computer to use.
pspssh v2.0.0 cobanov.dev pve [email protected]:2222 > macmini [email protected]:22 laptop [email protected]:22 + add a host X connect [] edit /\ delete SEL forget key O quit
What it does
- Modern cryptography, and only that. One algorithm per slot:
curve25519-sha256,ssh-ed25519,aes256-ctr,hmac-sha2-256. A weak session cannot be negotiated because there is nothing weak to negotiate. - Servers managed on the console. Add, edit and delete hosts with the on-screen keyboard. The list is written through a temporary file, so a battery pull halfway through adding one server cannot cost you the others.
- Host keys remembered. Trust on first use, then the same key every time. A change is refused with no override on that screen — getting past it means finding the host in the list and pressing SELECT, which is friction on purpose.
- An 80-column terminal. Colours, cursor addressing, erase, insert and delete, scroll regions. Spleen 6×12, because at sixty columns the output of
ls -lwrapped and stopped being columns. - Passwords are optional. Leave one out and it is asked for at connect time, then wiped.
Since 1.0.0
1.0.0 proved the handshake. Everything else is this release: the screen is drawn by the application rather than by pspDebugScreen, which is what made a keyboard and a terminal possible at all. Then the host list, the on-screen keyboard, the terminal, and the host key check.
Four hardware bugs were found and fixed along the way, each of which is a note in the source now:
- The clear raced the keyboard's own drawing — a CPU-side clear against GE-side rendering, with nothing sequencing them. A black screen instead of a keyboard.
sceUtilityOskGetStatusreturnspspUtilityDialogState, not theSceUtilityOskStatethat sits in the same header. Off by one from VISIBLE onward, so the keyboard was never refreshed while it was up.- Restricting the keyboard's input type is the least-travelled path in the dialog, and it is what made the port field refuse to open.
PARAM.SFO's key table has to be sorted, andAPP_VERhas to beXX.YY.
What stands behind it
122 assertions run without a PSP, over the four modules whose logic does not need one:
| | | |
|---|---|---|
| hosts.c | 35 | round trips, refusals, the legacy import, an interrupted save |
| knownhosts.c | 28 | matching, not matching, not matching a prefix, every way a file could load less than it claims |
| term.c | 43 | cursor addressing, erase modes, scroll regions, escape sequences split across reads, hostile parameters |
| console.c | 16 | wrapping, scrolling, tabs, a call larger than its own buffer |
Plus six against a real OpenSSH server, which check the fingerprint the client computes against what ssh-keyscan reports for the same host.
tools/release.sh builds from a fresh clone before tagging, because v1.1.0 shipped unbuildable.
Installing
Download EBOOT.PBP and copy it to the memory card as PSP/GAME/pspssh/EBOOT.PBP — ef0: on a PSP Go. Launch it from the XMB under Game and add your servers from the list. Your saved hosts and remembered keys are separate files and survive an upgrade.
A PSP does WEP and WPA-TKIP. WPA2-AES needs the wpa2psp plugin on 6.61 PRO; on ARK CFW it is already there.
Known
- Public key authentication is not implemented. Passwords only.
- Typing is line at a time, because the keyboard is a modal dialog. That suits
sh; it does not suitvim, and no amount of work on this client will change it. - The menu music has never played. It is in this build with the loop chunk Sony's encoder writes, which is untested — #51 records everything ruled out. Deleting
assets/SND0.AT3and rebuilding removes it and 199 KB.
Full changelog: https://github.com/cobanov/pspssh/compare/v1.0.0...v2.0.0
v1.1.2 · Jul 31, 2026
Fixes the black screen where the on-screen keyboard should be, reported from hardware on v1.1.1. Everything else in v1.1.1 is unchanged.
What was wrong
The clear raced the keyboard's own drawing.
osk.c cleared the screen by writing pixels with the processor, while sceUtilityOskUpdate draws through the graphics engine and queues its work asynchronously. Nothing sequenced the two, so a clear could land on top of a keyboard that had already been drawn — and since that happened every frame, the result was a black screen rather than a flicker.
The SDK sample avoids this because its clear is also a GE operation, so both go into one queue and execute in order. The keyboard loop now does the same. Everywhere else keeps writing pixels directly: nothing else draws into the buffer there, so there is nothing to be ordered against.
Two more faults were sitting behind it, either of which would have produced something similar alone:
PSP_UTILITY_OSK_DIALOG_NONEwas treated as "finished". It means no dialog is active, which is true before one has started as well as after it has shut down — so aNONEon the first frame ended the loop immediately and reported a cancellation that never happened.- The terminal passed no backdrop, so its background was black by construction. The host editor always drew its form, which is why this surfaced in the session and would have been obvious anywhere else.
What changed for you
The session now stays visible behind the keyboard, so you can see what you are typing against.
And if the keyboard still does not appear within five seconds, it is shut down and says so, rather than leaving you on a blank screen with no way back.
Installing
Download EBOOT.PBP below and copy it over PSP/GAME/pspssh/EBOOT.PBP — ef0: on a PSP Go. Your saved hosts and remembered keys are separate files and are not touched.
Full changelog: https://github.com/cobanov/pspssh/compare/v1.1.1...v1.1.2
v1.1.1 · Jul 31, 2026
A one-line fix to something v1.1.0 got wrong, plus the check that would have caught it. Everything below is v1.1.0's feature list — if you are installing for the first time, install this one.
The fix
third_party/ was gitignored, and src/psp/gfx.c includes the font from it. So the file every glyph on screen comes from was never in the repository, and git clone && tools/build-psp.sh failed at the first compile.
Nobody noticed because the file was sitting in the tree it had been written in. tools/release.sh now builds from a fresh clone rather than from the working tree, because the rule worth enforcing is not "the author can build it" but "this can be built from what was published".
The download below is unaffected — v1.1.0's EBOOT.PBP was fine, only the source tree was not.
What v1.1.x is
v1.0.0 proved a PSP Go could complete a modern SSH handshake. It also ran one hardcoded command, took its server from a text file you had to edit on a laptop, and printed the host key's fingerprint without checking it against anything. All three are fixed.
Servers live in the application
pspssh v1.1.1 Mert Cobanov pve [email protected]:2222 > macmini [email protected]:22 laptop [email protected]:22 + add a host X connect [] edit /\ delete SEL forget key O quit
Add, edit and delete hosts with the system on-screen keyboard. The list is written through a temporary file and moved into place, so a battery pull halfway through adding one server cannot cost you the others.
Storing a password is a choice. Leave it empty and you are asked at connect time, and it is wiped afterwards.
A terminal, not a printout
Colours, cursor addressing, erase, insert and delete, scroll regions. What a shell sends, drawn the way a shell means it, instead of ESC[0;32m appearing where a green prompt should be.
Typing is line at a time, because the keyboard is a modal dialog. The buttons carry what a line cannot: Enter, Ctrl-C, Ctrl-D, Tab, Escape, Ctrl-L, and the arrow keys on the d-pad — so shell history works.
Host keys are checked
Trust on first use, then the same key every time. A change is refused, with no override on that screen: on a handheld that button is pressed before it is read, and it is the only moment an interception is visible.
Servers do get rebuilt, so a key can be forgotten — from the host list, with SELECT, behind a confirmation. Deliberately not next to the alarm it silences.
Under it
The screen is drawn by this application now rather than by pspDebugScreen, which is what made a keyboard and a terminal possible at all — the on-screen keyboard renders into the GU draw buffer and the debug console knows nothing about one.
Three modules have no hardware in them, so 106 assertions run on a laptop: the storage layer, the host key check, and the escape-sequence parser. Plus six against a real OpenSSH.
Also fixed since v1.0.0: the handshake timeout counted loop turns and called them milliseconds; the version constant named a build that was not running; the config reader stopped at 1023 bytes without saying so; and the application compiled wolfSSL's headers as a different build from the library it links against.
Installing
Download EBOOT.PBP below and copy it to the memory card as PSP/GAME/pspssh/EBOOT.PBP — on a PSP Go the internal storage is ef0: rather than ms0:. Launch it from the XMB under Game and add your servers from the list.
A PSP does WEP and WPA-TKIP. WPA2-AES needs the wpa2psp plugin on 6.61 PRO; on ARK CFW it is already there.
Full changelog: https://github.com/cobanov/pspssh/compare/v1.0.0...v1.1.1
v1.1.0 · Jul 31, 2026
The client you can actually use without a computer nearby.
v1.0.0 proved a PSP Go could complete a modern SSH handshake. It also ran one hardcoded command, took its server from a text file you had to edit on a laptop, and printed the host key's fingerprint without checking it against anything. All three are fixed.
Servers live in the application now
pspssh v1.1.0 Mert Cobanov pve [email protected]:2222 > macmini [email protected]:22 laptop [email protected]:22 + add a host X connect [] edit /\ delete SEL forget key O quit
Add, edit and delete hosts with the system on-screen keyboard. The list is written through a temporary file and moved into place, so a battery pull halfway through adding one server cannot cost you the others.
Storing a password is now a choice. Leave it empty and you are asked at connect time, and it is wiped afterwards — which was always the safer arrangement and was impossible while typing meant a computer.
A terminal, not a printout
Colours, cursor addressing, erase, insert and delete, scroll regions. What a shell sends, drawn the way a shell means it, instead of ESC[0;32m appearing where a green prompt should be.
Typing is line at a time, because the keyboard is a modal dialog. The buttons carry what a line cannot: Enter, Ctrl-C, Ctrl-D, Tab, Escape, Ctrl-L, and the arrow keys on the d-pad — so shell history works.
Host keys are checked
Trust on first use, then the same key every time. A change is refused, with no override on that screen: on a handheld that button is pressed before it is read, and it is the only moment an interception is visible.
Servers do get rebuilt, so a key can be forgotten — from the host list, with SELECT, behind a confirmation. Deliberately not next to the alarm it silences.
Under it
The screen is drawn by this application now rather than by pspDebugScreen, which is what made a keyboard and a terminal possible at all — the on-screen keyboard renders into the GU draw buffer and the debug console knows nothing about one.
Three modules have no hardware in them, so 106 assertions run on a laptop: the storage layer, the host key check, and the escape-sequence parser. Plus the existing six against a real OpenSSH. What still needs a PSP is a screen, a radio and a system keyboard.
Also fixed: the handshake timeout counted loop turns and called them milliseconds; the version constant named a build that was not running; the config reader stopped at 1023 bytes without saying so; and the application compiled wolfSSL's headers as a different build from the library it links against.
Installing
Download EBOOT.PBP below and copy it to the memory card as PSP/GAME/pspssh/EBOOT.PBP — on a PSP Go the internal storage is ef0: rather than ms0:. Launch it from the XMB under Game and add your servers from the list.
A PSP does WEP and WPA-TKIP. WPA2-AES needs the wpa2psp plugin on 6.61 PRO; on ARK CFW it is already there.
Full changelog: https://github.com/cobanov/pspssh/compare/v1.0.0...v1.1.0
v1.0.0 · Jul 31, 2026
A PSP connects to a modern SSH server.
Confirmed on a PSP Go running 6.61 PRO-C: Wi-Fi up, socket open, curve25519-sha256 key exchange, ssh-ed25519 host key verified, password authentication, a pty, a shell, and its output on screen. The server's own log says Accepted password and Starting session: shell.
Why this needed writing
PSPSSH, the existing client, is a 2008 port of Dropbear 0.48. It offers diffie-hellman-group1-sha1, ssh-rsa and aes128-cbc — none of which a current OpenSSH accepts by default, so it cannot reach a modern server at all. The fix is not to weaken every server you own.
What it negotiates
curve25519-sha256 key exchange ssh-ed25519 host key aes256-ctr cipher hmac-sha2-256 MAC
Pinned to exactly those, one name per slot. In the captured handshake the server offered 1256 bytes of algorithms including post-quantum sntrup761x25519-sha512; the console offered 168. A weak session cannot be negotiated because there is nothing to fall back to.
Installing
Copy EBOOT.PBP and pspssh.cfg to ms0:/PSP/GAME/pspssh/ — on a PSP Go the internal storage is ef0:. Edit pspssh.cfg with your server, launch it from the XMB under Game.
Needs custom firmware and a Wi-Fi connection already saved in the PSP's own network settings. The app lists what it finds and tries them in turn, so the profile number does not have to be guessed.
What it does not do yet
There is no keyboard. It reads the server from a config file, runs uname -a; id and shows the output on the debug screen — enough to prove a session carries real output, not yet a terminal you can type in. An 80×30 grid is #4 and input is #2.
The host key is displayed but not remembered, so a changed key is not yet refused.
pspssh.cfg holds the password in plain text on a memory card. Use an account you are willing to have on a games console.
v0.4.1 · Jul 31, 2026
SO_NONBLOCK is defined as 0 on the PSP. So the call that was supposed to make the socket non-blocking set option zero and changed nothing — and a blocking recv on a quiet socket never returns, which is a frozen screen you cannot tell from a crash. Readiness now comes from select(), as in the SDK's own samples.
The handshake loop now yields and has a deadline. A retry loop that never gives up the processor can starve the thread delivering the bytes it is waiting for. It also stops after 30 seconds rather than looking like work still in progress.
Wi-Fi failures now report the furthest state reached, not the last. A connection that got to state 2 and fell back to 0 was being described as "never started", which points at the wrong problem entirely. It now separates three cases:
- never started — no saved connection at that number
- scanned but never found it — wrong SSID, or not on 2.4 GHz
- found it and was refused — nearly always the security type. A PSP does WEP and WPA-TKIP; WPA2-AES needs the
wpa2pspplugin loaded.
Also tools/wire-probe.py, which listens on the host and dumps every byte a client sends with timestamps — the container's NAT hides the real client address, so the server log could not tell a PSP from a laptop.
v0.3.2 · Jul 31, 2026
The first thing on screen now says what it is, which build, and who made it:
pspssh v0.3.2 - Mert Cobanov ssh for the psp: curve25519, ed25519, aes256-ctr ------------------------------------------------------------
The third line is the point of the project stated where someone will read it: the PSP's existing SSH client speaks 2008 cryptography and cannot reach a current server. This one does.
Everything else is 0.3.0 — the jitter-based entropy source that lets a session be created at all, and --enable-harden on both builds.
Copy EBOOT.PBP to ef0:/PSP/GAME/pspssh/. If the banner does not say v0.3.2, the copy did not take.
v0.3.1 · Jul 31, 2026
The first line on screen is now pspssh 0.3.1.
The install is a file copied by hand onto a memory card, so running a stale binary is a normal occurrence — and until now the only way to tell which build was on the device was which error message appeared. That works by accident and stops working as soon as two builds fail the same way.
Everything else is 0.3.0: the jitter-based entropy source that finally lets a session be created, and --enable-harden on both builds.
If the first line says anything other than pspssh 0.3.1, the copy did not take.
v0.3.0 · Jul 31, 2026
Sessions now have something to be built from.
On hardware every connection died with wolfSSH session could not be created. Asking the RNG directly named it: wc_InitRng gave RNG_FAILURE_E (-199). A PSP has no /dev/urandom and no hardware random number generator, so wolfSSL had nothing to seed from and no session could be created at all.
src/psp/entropy.c harvests timing jitter — a small unpredictable amount of work measured against the microsecond clock, hundreds of times, hashed into a SHA-256 pool with per-boot values, output ratcheted forward.
It is deliberately not called a random number generator, and it refuses rather than guesses: it counts how often the timing actually changed and fails if the clock does not jitter. A pool seeded with nothing still produces bytes that look fine, and those would be a guessable session key.
wolfSSL also warned that timing resistance was off, so both builds now use --enable-harden.
Same install as before — EBOOT.PBP into ef0:/PSP/GAME/pspssh/. Your pspssh.cfg is not overwritten.
v0.2.1 · Jul 30, 2026
Profile discovery worked on hardware. What followed it was a blank screen, because connect() blocks until the kernel's TCP timeout and nothing said so.
- The lookup and the connection announce themselves, with the address actually being dialled.
- So does the key exchange — curve25519 and an ed25519 signature on a 333 MHz MIPS take a moment, and silence there reads as a hang rather than as work.
- Rebuilding no longer overwrites
pspssh.cfg. It is written only when absent.
The bundled config points at the project's test server on 192.168.8.45:2222 with profile=2. Change host to yours.
v0.2.0 · Jul 30, 2026
It no longer guesses which saved Wi-Fi connection to use.
A profile that works in the PSP's own browser could still be refused, because deleting a connection in the settings does not necessarily renumber the ones after it — so the remaining one is not reliably number 1.
The app now lists what the device actually has, with names and SSIDs, tries the configured profile first and then every other one, and tells you which worked so pspssh.cfg can be corrected once.
saved connections: 1: home (ssid cobaniv-iot) 2: guest (ssid cobaniv-guest)
Failed attempts disconnect before the next begins, so a second try does not inherit a half-open association.
The bundled pspssh.cfg points at the project's own test server. Edit host to yours.
v0.1.1 · Jul 30, 2026
Diagnostics for the first hardware run, which produced gave up waiting for wifi state 0 and nothing more.
profile=Ninpspssh.cfg— the Wi-Fi connection's position in the PSP's own network settings, no longer hardcoded to 1.- Thirty seconds instead of ten — a cold 2.4 GHz scan plus DHCP takes longer than the first guess, and giving up early reports a working network as a broken one.
- The state is printed as it changes — 0 means it never started, 1 and 2 mean it is associating, 3 means it is waiting for an address. Four different problems that used to be one message.
If you see state 0: the network existing on your router is not enough. The PSP needs its own saved connection under Settings > Network Settings > Infrastructure Mode, and profile must be its position in that list.
v0.1.0 · Jul 30, 2026
An SSH client for the PSP that talks to a current OpenSSH server.
The existing PSP client, PSPSSH, is a 2008 port of Dropbear 0.48 and offers diffie-hellman-group1-sha1, ssh-rsa and aes128-cbc — none of which a modern OpenSSH accepts by default. This one negotiates:
curve25519-sha256 key exchange ssh-ed25519 host key aes256-ctr cipher hmac-sha2-256 MAC
Pinned to exactly those, so a weak session cannot be negotiated rather than merely noticed afterwards. Verified end to end against a real OpenSSH from the host, including that the host key fingerprint matches what the server reports for itself.
Installing
Copy EBOOT.PBP and pspssh.cfg to the memory card as PSP/GAME/pspssh/ — on a PSP Go the internal storage is ef0: rather than ms0:. Edit pspssh.cfg with your server, then launch it from the XMB under Game.
Needs custom firmware, and a Wi-Fi profile already saved in the PSP's own network settings — the app selects profile 1, it does not join a network itself.
What this build does and does not do
It connects, authenticates with a password, runs uname -a; id and shows the output on the debug screen. That is enough to prove the session carries real output.
It does not yet have a terminal grid (#4) or any input (#2) — typing on a device with no keyboard is the unsolved problem, which is why the server comes from a config file.
pspssh.cfg holds the password in plain text on a memory card. Use an account you are willing to have on a games console.
Not yet run on hardware. If it fails, that is the interesting part — please open an issue.
