I figured out why I'm getting this error, even though my donor key is valid. Turns out the server doesn't seem to like my blog name, which contains an escaped character.

Response:
<?xml version="1.0"?>
<methodCall>
<methodName>mtUpdates.ping</methodName>
<params>
<param><value><![CDATA[JOHN R CHANG &gt; Weblog]]></value></param>
<param><value>http://www.68k.org/~jrc/blog/</value></param>
<param><value>XXXXXXXXXXXXXXXX</value></param>
</params>
</methodCall>


Request:
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>flerror</name>
<value>
<boolean>1</boolean>
</value>
</member>
<member>
<name>message</name>
<value>Invalid donor key ''</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>


Changing the character in the blog name from "&gt;" to ">" or something else ("|") fixes the problem.