Code Review lulzlabs Radio AirChat - Updated 04.10.2016 13:37

Yesterday someone announced AirChat on the cypherpunks mailinglist. He didn't provide any comment as to what it is or why he posted it. However I took a look anyway. I found some really odd piece of software and decided to publish a review about it. Please note, that I only looked at the code. I didn't install it and I didn't run it (I've got no radio device anyway). So, this review is not about usage, user interface or something, it's only about the code and the security implications from what I found there.

What is AirChat radio?

AirChat is a perl script and according to their README, it can be used to communicate encrypted via radio signals. No internet or mobile required, so they say.

Summary

The code in the script is a mess. One monolithic script which contains keys, configuration, html code, css code, almost no comments. It ignores all perl standards of perl software distribution (build, packaging, unit tests, documentation). The script has obviously been written by different authors (or the main author copy/pasted code from somewhere else) in different styles and paradigmas. It looks much like the old perl scripts of the late 1990s. AirChat is one of the worst security softwares I've ever seen. I would not encourage anyone using it.

Source Organization

Essentially, there's none. The software consists of one file (airchat.pl), which contains everything, like modules, html code, configuration, daemon code, ui code, hardware interfacing code and so forth.

AirChat completely ignores all perl standards about how to distribute perl software. There's no MakeMaker Makefile.PL, there are no unit tests and practically no documentation. The README file consists in large parts of prosa text, where the author(s) tell about their motives to create the software. Though it contains information how to install the software, there is no single hint about usage beside telling the user to connect with the browser to localhost to some port.

 

Coding Style

The script uses both whitespace and tabs for indentation. As a result the overall code looks messy, sometimes it's difficult to read it. Here's an example:

(the long underscored lines come from emacs syntax highlighting, these are whitespaces)

The script is also styled in different ways. I'd assume it have been written by different authors or the author used code from somewhere else.

The AirChat script uses some very - ahem - weird variable names. Here are some examples:

my $cock;
$settings->{'settings'}{'penis'}{'penis'} = 'also cocks' ;
my $penispenis = " ";
%dahfuckingkeys = %{$getem};
my @sortedshit = split("##END##",$pack);
$dahpassiez = Crypt::CBC->random_bytes('4096');

Obviously the author is fixated on male sexual organs. Another example of this are the modem_* functions. For example the function modem_setting() returns the literal string "penis" as do several others for no reason. Function names follow this pattern as well. Some examples: sendthefuckout(), resenditpl0x() or gogogodispatch().

Beside variables there are also gems like this:

 if ($mustEncrypt eq "yeahbabygetthisoneintoyourassFCCandNSA") {

Comments in the code are rare. When there is a comment, it comments the obvious in most cases or is just senseless. An example:

	## youz taking drugz again 

Because of missing comments and no code documentation in general it is difficult to follow the program flow in order to figure out, what the script does.

Perl

The perl code in airchat.pl is inefficient, hard to read, inconsistent and old styled. One good thing can be noted though: the author has enabled strict and warnings, and uses my (or our) keywords to avoid undefined behavior. In most cases he also checks for validity. However there's not much error handling in the script. That is, an action will be done if a variable X is set, but there's no code for the case when it isn't. That's not always the case, but can be found all over the script. Here's one example of poor error checking (and reporting):

	eval{$ctx = $cipher->encrypt($txpack)};
	eval{$useThisk = $cipher->encrypt($useThisk)};
	if ($@) {
	  print "error encrypting";
						
	} else {
        [..]

Only the eval() error of the second encrypt call is being checked. If the first one fails gets ignored. It's also not clear why he's using eval() at all.

airchat.pl contains lots of global variables and some of them are scattered throughout the script. I counted 76 global variables, however, some of them are part of the module AirChatServer (contained within the script).

It is obvious that the author is inexperienced when it comes to perl data structures. Here's a snippet of the function load_settings():

    $proxyhost = $settings->{'settings'}{'Tor and Proxy'}{'proxyhost'}  if defined  $settings->{'settings'}{'Tor and Proxy'}{'proxyhost'}  ;
    $proxyport = $settings->{'settings'}{'Tor and Proxy'}{'proxyport'}  if defined  $settings->{'settings'}{'Tor and Proxy'}{'proxyport'}  ;
    $proxyuser = $settings->{'settings'}{'Tor and Proxy'}{'proxyuser'}  if defined  $settings->{'settings'}{'Tor and Proxy'}{'proxyuser'}  ;
    $proxypass = $settings->{'settings'}{'Tor and Proxy'}{'proxypass'}  if defined  $settings->{'settings'}{'Tor and Proxy'}{'proxypass'}  ;

That's a lot of repeated typing. In general, the author uses a global hash %settings to store configuration which is to be saved to a configuration file, but doesn't use that hash. Instead he assigns every single value in that hash to a single global variable. He does the reverse when saving it to the configuration file.

Despite the notion of Windows in the documentation, the script isn't portable, since it's using hardocded unix filesystem separators:

 open(F, '<', "$foolder/.AirChatsettings") or die "cannot open file settings";

Instead he should use the File::Spec perl module which does stuff like this in a portable way. There's also no check if the configuration directory, which is the script location, is writable (save_settings()). The same applies for saved messages (whatever kind of message it tries to save) and saved public keys.

The author is not very familiar with regular expressions as well. Let's take a look at this example:

if ($kxcode[1] =~ m/:CTALK2:[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]/ ) {

He's essentially checking for a hex value, but he doesn't know of perl regex quantifiers, such as: [0-9a-f]{6}. Variations of the above regex can be found throughout the whole script. There's another issue which the above line shows us: hardcoded values. And there are lots of them. Things like "OHAITHERE" or "HOTELINDIA", sizes, protocol codes (I'll come to that later) and stuff like this. Here's an example of a hardcoded size value:

my $kidx = substr($kidx,0,6);

Here the author extracts the first 6 chars of a hexstring and uses it as a key id (see below). Key id extraction code like this is scattered overall in the script, everwhere using the hardcoded 6.

Speaking of hardcoded stuff. airchat.pl contains a webserver as well (it's being used to interface to the user, I think) and a couple of builtin CGI functions. Those functions use print() statements to put HTML out. Lots of them. The author seems to be not very familiar with HTML as well, eg:

 print qq {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/addKey" ><code>add a new key</code></a>};

There's even an embedded font file (base64 encoded). Maintaining that stuff must be very hard. Since the HTML and style is hardcoded in the script it can't be customized (if a user wanted to do that) or translated.

There are a lot more issues. I just covered a couple of them.

Security

The airchat.pl script is completely unsecure despite the repeated "fuck the NSA" references here and there in the script and the README. It's (trying to) use RSA and AES and Camilla Ciphers along with SHA2 for hashing. When looking at the code, it looks like it's using RSA public key crypto to exchange keys with peers (via radio?). However, it's not using it at all. The reason is, that every encryption key for symmetric encryption, which is being used to encrypt messages, uses hardcoded keys. Here are the keys I found:

  •  'b0ssjP3n1s+d2y0l0+IATTsuxiOB1vz7 - being used in asym_encrypt(), asym_decrypt(), sendinghits(), gettingdecodedmsg()
  •  'x3UstrV@Hl;Mm#G9#_q,suckXZ$O^;55jlT*' - used as passphrase with Crypt::CBC.
  • there are twitter API keys in the script!

Basically the script encrypts a randomly generated ephemeral key using RSA but then ignores it and uses the above hardcoded key for symmetric encryption. SeeUpdate below!

Random bytes are always generated this way:

 $dahpassiez = Crypt::CBC->random_bytes('4096');

He should have been using Crypt::Random or Bytes::Random::Secure instead. From the Crypt::CBC docs:

$data = random_bytes($numbytes)

Return $numbytes worth of random data. On systems that support the "/dev/urandom" device file, this data will be read from the device. Otherwise, it will be generated by repeated calls to the Perl rand() function.

Beside those two major issues it generates key id's in a bad fashion:

 my $rsa = Crypt::OpenSSL::RSA->generate_key(2048);
 my $keyidx = $rsa->get_public_key_string() if defined $rsa;
 $keyidx = sha512_hex($keyidx,"");
 $keyidx = substr($keyidx,0,6);

Basically (as already mentioned earlier) he's using the first 6 characters of the hex encoded hash of the hex encoded RSA public key string. What could possibly go wrong?

Another issue with the above code is that it would generate a keyid from undef if RSA key generation fails for some reason. And it would store it anyway.

Another problem is, that all key material is being stored on disk without permission setting or checking. So the script will use the current umask, which would be 0644 for most users, therefore leaving the keys open to fetch for other users of the system.

There seems to be no key expire mechanism as well. Once generated a key will be used forever. At least in theory, since the RSA keys are not used anyway as mentioned above.

 

Other Oddities

Despite being a tool for encrypted radio communication the script contains code for Twitter publishing (with hardcoded API keys but they can be changed though), it fetches RSS feeds from various websites (hardcoded URIs of course), e.g. from NY Times.

But it supports using a TOR proxy after all.

 

Conclusion

By just using a mobile phone the user can communicate more secure via radios signals. Since every encryption is being done with the same hardcoded key, it is completely useless. If the author(s) fix at least the hardcoded key and random number generation issue, then the tool could have a future. See Update below!


Update 04.10.2016 13:37:

After someone responded to some of the issues in a github issue and said, that my finding that AirChat uses hardcoded keys is wrong, I did some further tests:

#!/usr/bin/perl
use Crypt::CBC;
use MIME::Base64;
my $k1 = "eins";
my $k2 = "zwei";
my $cl = "hallo";
my $c1 = Crypt::CBC->new({ key => $k1 });
$c1->{passphrase} = $k2;
my $en = $c1->encrypt($cl);
my $c2 = Crypt::CBC->new({ key => $k2 });
printf "clear: %s decr: %s",
  encode_base64($cl),
  encode_base64($c2->decrypt($en));
This prints:
 % ./t.pl 
clear: aGFsbG8=
 decr: aGFsbG8=
So, as it seems, if you set the HASH parameter Crypt::CBC::passphrase after the object has been initialized with a key parameter, the latter will be used by the module.

Therefore my conclusion that the tool is insecure because of hardcoded keys was wrong. It might still be insecure because of other reasons though, but this is not part of this update. However, it is confusing for the casual reader to see those hardcoded (but, as I now found, unused) keys in the code. In fact I only made the review in the first place because of this.


25.04.2014 20:07 CC0 kritik security Source






Rainbow Shiner Aufzucht - Updated 17.08.2014 12:31

Wie neulich erwähnt, sind ja meine Rainbow Shiner ausgezogen. Allerdings haben die kurz vorher noch im Quarantänebecken einen ziemlichen Tanz hingelegt. Tja, und was soll ich sagen - es gibt Nachwuchs.

Die Babies sind jetzt eine Woche alt und schwimmen seit gestern frei, etwa 15 Stück. Die sind wahnsinnig winzig, nur 5mm lang, einen halben dick und komplett durchsichtig. Man findet sie kaum. Nichts desto Trotz sind mir ein paar Bilder gelungen:

Bild: Shiner Babies 1
Shiner Babies 1 (April 24, 2014, 8:07 p.m.)
[Tags: quallen quarantaene rainbowshiner ] [Album: Aquarium ]
Bild: Shiner Babies 2
Shiner Babies 2 (April 24, 2014, 8:07 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Shiner Babies 3
Shiner Babies 3 (April 24, 2014, 8:07 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]


Update 25.05.2014 14:10:

Nun ist ein Monat vergangen und den Babies geht es noch immer gut. Sie wachsen, allerdings recht langsam. Aktuell sind sie zwischen 1,5 und 2 cm lang. Ich habe aber auch zwei Nachzügler entdeckt, die anscheinend gerade eben erst geschlüpft sind. Keine Ahnung, wie die Eier sich solange haben halten können.

Bild: Shiner Babies nach 1 Monat 1
Shiner Babies nach 1 Monat 1 (May 25, 2014, 2:12 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Shiner Babies nach 1 Monat 2
Shiner Babies nach 1 Monat 2 (May 25, 2014, 2:12 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Shiner Babies nach 1 Monat 3
Shiner Babies nach 1 Monat 3 (May 25, 2014, 2:12 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]


Update 13.08.2014 19:39:

Inzwischen sind sie fast erwachsen und haben einen Mordsappetit. Bald werde ich sie abgeben (sofern sich jemand für sie findet, heisst das).

Bild: Shiner Babies nach 5 Monaten
Shiner Babies nach 5 Monaten (Aug. 13, 2014, 7:40 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]


Update 17.08.2014 12:31:

So, heute habe ich die Rabauken abgegeben. Damit ist das Kapitel Rainbow Shiner für mich abgeschlossen. Schade, denn das sind tolle Fische.


24.04.2014 20:04 CC0 aquarium rainbowshiner Aquarium






Movies to look 2014

Just a loose list mere to myself:

However, as always these days, I'm constantly asking myself, why don't they use one of the thousands of good SciFi novels as the base for SciFi movies?


22.04.2014 19:43 CC0 scifi Gefunden






Neue Bewohner

Seit vorgestern habe ich neue Bewohner im Becken, Kardinalfische:

Bild: Kardinäle
Kardinäle (April 13, 2014, 11:50 a.m.)
[Tags: fische ] [Album: Aquarium ]

13.04.2014 11:49 CC0 aquarium2013 fische Aquarium






Der Erwin wurde wieder gesichtet!

Gestern Nacht hab ich mal wieder den Erwin gesichtet! Yeah!

Bild: Erwin von unten
Erwin von unten (April 12, 2014, 7:41 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin von der Seite
Erwin von der Seite (April 12, 2014, 7:42 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin versteckt sich
Erwin versteckt sich (April 12, 2014, 7:42 p.m.)
[Tags: firefox ] [Album: Aquarium ]
Bild: Erwin und ein Panzerwels
Erwin und ein Panzerwels (April 12, 2014, 7:44 p.m.)
[Tags: fische ] [Album: Aquarium ]

12.04.2014 19:32 CC0 aquarium2013 fische Aquarium






Letzter Tag Rainbow Shiner - Updated 10.04.2014 17:19

Ich habe lange mit mir gerungen, aber es nützt nichts. Die Rainbow Shiner müssen leider ausziehen. Inzwischen ist nur noch die Hälfte am Leben, der Rest ist im Lauf der Zeit - trotz aller Maßnahmen - aus dem Becken gesprungen. Ich werde die morgen gegen Kardinäle eintauschen.

Weil die Shiner recht schwer zu fangen sind, hab ich schon gestern angefangen, sie aus dem Becken zu fischen. Bis morgen sind sie in einem kleinen Quarantänebecken untergebracht. Und was sie da jetzt machen, hat mir den Atem verschlagen. Zunächst sind einige von ihnen heftig orange geworden - das ist die Paarungsfärbung. Weil das Becken sowieso ansonsten leer ist, hab ich ihnen halt noch ein paar Kieselsteine reingetan. Wir erinnern uns: Rainbow Shiner verwenden in ihrer Heimat die Kieselnester von grösseren Barschen zum Ablaichen.

Und DANN ging es richtig los. Gerade so, als ob sie mir sagen wollen: Du willst uns weggeben? Ok, dann zeigen wir Dir nochmal, was wir drauf haben:

Bild: Rainbow Shiner Paarung 1
Rainbow Shiner Paarung 1 (April 10, 2014, 3:32 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Rainbow Shiner Paarung 2
Rainbow Shiner Paarung 2 (April 10, 2014, 3:32 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Rainbow Shiner Paarung 3
Rainbow Shiner Paarung 3 (April 10, 2014, 3:32 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]
Bild: Rainbow Shiner Paarung 4
Rainbow Shiner Paarung 4 (April 10, 2014, 3:32 p.m.)
[Tags: rainbowshiner ] [Album: Aquarium ]


Update 10.04.2014 17:19:

Oh, und ich habe auch ein Video gemacht, als Andenken sozusagen:








Generation Ritalin Franfurt Ostendstrasse - Updated 02.03.2014 22:57

Heute im Vorbeigehen an der S-Bahnstation Franfurt Ostendstrasse entdeckt:

Bild: Generation Ritalin
Generation Ritalin (March 2, 2014, 10:54 p.m.)
[Tags: foto ] [Album: shots ]


Update 02.03.2014 22:57:


02.03.2014 22:52 CC0 foto Gefunden






Vereinfachter europäischer Zahlungsverkehr

Der vereinfachte europäische Zahlungsverkehr sieht bei mir so aus:

Bild: falsche IBAN
falsche IBAN (Feb. 24, 2014, 4:32 p.m.)
[Tags: idioten ] [Album: Screencaps ]

24.02.2014 16:31 CC0 idioten kritik Gesellschaft






PCP API Documentation and more changes - Updated 04.03.2014 23:10

During the last weeks I made lots of changes to the PCP code. Most of it was refactoring of internal stuff. First, I implemented a C Buffer "class", inspired by OpenSSH's buffer.c. I really like it. It can be used to incrementally fill a buffer, the buffer resizes automatically and makes boundary checks on every call to avoid buffer overflows. I can also directly put numbers of different sizes into it and multibyte numbers can be converted to big-endian automatically. The same prinziples can be used in the reverse, it's possible to read from a buffer little chunks. It remembers the last read offset and also supports host-endian conversion.

On top I wrote a C stream "class". This one is even nicer, since it can be used to read/write from/to files OR buffers. It behaves almost like the FILE interface, you can use ps_write() to put data out or ps_read() to fetch data in. That way I can do blockwise encryption on files and memory buffers. In fact, the encryption API uses those streams. But the latest addition to the stream class is even better: it can transparently encode to Z85 encoding. And in read-mode it can decode and determine automatically if the input is encoded. I'm not using it in the API yet, but the sample program already uses it and it works like a charm.

As you can see from the various links in this post, I also added some fairly amount of API documentation which is available here for online reading. It's generated using doxygen and I love it.

What else? I changed the sign and crypt mode of pcp, it signs the recipient list and a hash of the original content, and encrypts the signature. I re-factored some of the Z85 code to be more reliable and fault tolerant. I changed the native format of PCP public key exports. Public keys are now exported in RFC4880 (OpenPGP) format. While my exports are incompatible with OpenPGP (which is not intended anyway), the format is much more flexible than my old format. Previously I just dumped the pubkey C-structure to disk. While that worked well, it's completely impractical if I ever change that structure (which I did a lot so far). Now with the RFC4880 format, exported keys are indepentent from the internal structure, therefore I can change it as I wish without ever getting incompatible to old exports.

While I was at it, I also changed the export format of secret keys. While I don't use RFC4880 for this, I use at least a much more formalized format and not just a structure dump. Also, the whole export is now encrypted, not just the secret key blobs inside.

Last but not least, you can now export public keys in a couple of programming languages, such as a perl structure, or C code or YAML. That way an exported key can be used in small programs without the hassle of generating and maintaining keys. Just use PCP for key management.

As always latest source is on Github.


Update 28.02.2014 17:24:

During the last days I made another large change, I changed the header markers for Z85 encoded data. Until now I had something like
----- BEGIN blah...-----
just as it's being used in PEM and elsewhere. This is no problem at all for small files like keys. But I wanted to have armored encryption as well, and there I fell heavily on my nose, including bleeding, crying and cursing of course.

The thing is, that the hyphen is a legitimate Z85 character and it may happen that ----- is legitimate Z85 encoded content. Proof:

$ perl -e 'foreach ((0xc6, 0x5a, 0x0b, 0x13)) { print chr($_) }' | pcp1 -z
-----
And since I'm reading input in streaming mode, it may happen that such a marker crosses block boundaries. So, I had to solve this. And my solution was quite genious or so I thought *g*. I just used the tilde character as marker which is not part of the Z85 characterset. One tilde starts a comment, another finishes it. Really easy. I had not much to change and it worked like a charm, even via block boundaries.

However, I spoke with Pieter about the issue and basically he told me, that my idea was bad (he said: "badly-designed parser"). Well. As of this writing the tilde-mode code is on github, but I already started to rewrite it. Again! Holy shit.

So in the next iteration (hopefully the last one, it's a boring business), I'll use hyphens again but read the streams in a totally different way. In fact if an input stream is considered Z85 encoded, it will be read linewise by the decoder. The decoder parses every line then and that way it's easily possible to detect headers, comments and footers. Once a Z85 block is complete, it will be decoded and put into the internal read cache. If there is something left on the line, it will be saved for the next iteration. So in fact, there are now 2 caches, one for decoded data (used by the caller) and one for undecoded data (kind of read ahead cache).

It's not done yet and I'm sure this stuff will steal me another couple days. Damn. However, at least it's currently in a state where it can parse and decode a complete stream. But I didn't try it with different blocksizes and I didn't even dare to run the unittests yet.

The new code isn't pushed to github so far, because yesterday I had a major problem with git. Thanks god I managed to solve it. "git merge", goddamnshit.


Update 02.03.2014 10:41:

So, finally I reverted the tilde stuff successfully. Now, PCP uses hyphens again. While I was at it, I enhanced the decoder and parser a lot. It's now more robust and parses the input linewise. Both the pcpstream decoder and the string decoder (z85_readstring()) now use the same framework. Previously they were independent from each other, so in fact I had two parsers. This was odd anyway so I generalized it.

The only remaining bad thing are clear signatures. They are parsed directly in ed.c and not by the stream decoder. I need to extend the stream decoder to be able to work on that stuff as well.

This Github commit was the last change to get into a stable state again. All unittests pass again. Thanks god (and my wife for her patience!)


Update 02.03.2014 23:11:

While I was at it, I fixed a couple of other encoding related bugs, added unittests for it, enhanced the commandline a little and added a verbose key listing feature (someone on cypherpunks requested it). Usually a key listing looks like this:

pcp1 -l
Key ID               Type             Creation Time        Owner
0xB5B64D99AE73F3BE   primary secret   2014-03-02T23:14:23  Mallory 
0x629AFD2418EFA3BA   secret           2014-03-01T18:50:06  Alicia 
0x969D5931D7B409C6   valid public     2014-03-01T18:50:07  Bobby 
0x4EF5795E2874AD8D   valid public     2014-03-01T18:50:09  Bart 
Note the validity new flag for public keys.

Now, the new verbose listing:

pcp1 -L
Key ID               Type             Creation Time        Owner
0xB5B64D99AE73F3BE   primary secret   2014-03-02T23:14:23  Mallory 
    88b3a815 49c28236 7e6e3c31 17c286c5 7905c7a7 ec78911f 1fd76563 5688e4c0 
    encrypted: yes, serial: c940b8f0, version: 6

0x629AFD2418EFA3BA   secret           2014-03-01T18:50:06  Alicia 
    076f002c 37b39ab5 cb0818b7 1fe33168 38b4d7d6 1b6e52c2 25229159 5405ec86 
    encrypted: yes, serial: 5386733f, version: 6

0x969D5931D7B409C6   valid public     2014-03-01T18:50:07  Bobby 
    2d1efc28 ef294913 06a914be 986975d9 869d01e1 82ea026f a4c16c98 b6a2e2bb 
    signed: yes, serial: f7cb26b4, version: 6, signature fingerprint:
    324fde54 3f6725ee a8c74f67 998e5b61 10a6f2db cdb2f282 1a689be2 3af1e514 

0x4EF5795E2874AD8D   valid public     2014-03-01T18:50:09  Bart 
    9b660a1b a688d8fa 4a3b3a02 78b75363 70d01656 30045245 55d74944 f08bb5ab 
    signed: yes, serial: 1b4ed012, version: 6, signature fingerprint:
    5449b8f4 9f0fe50e 3e46c1be e9225e26 aa1354bf 6bd105c3 147a9870 8a531161 
Basically it displays the fingerprint of the keys, some flags and - if present - the key signature fingerprint. I store the signature anyway but didn't use or display it yet.


Update 04.03.2014 23:10:

I've got the last big change done, I removed -P and -S, now keys of any type are imported with -K. The new importer uses the Pcpstream decoder as well, so the last remaining part which isn't using it, is the clearsig reader. I also fixed more bugs in the decoder.


23.02.2014 11:13 CC0 crypto pcp privacy software Source






Auferstanden von den Toten

Vor vielen Monaten, eher einem halben Jahr, habe ich von einem Freund einen Kammdornwels übernommen. Er hat sein Becken abgeschafft, alle Fische abgegeben, nur ihn wollte niemand haben. Ich hatte ihn damals in mein Becken getan und seither nie wieder gesehen. Mir wurde zwar versichert, dass der sich selten blicken lässt und wenn, dann nur nachts. Aber ich habe ihn nie zu Gesicht bekommen.

Tatsächlich war ich felsenfest davon überzeugt, dass er gestorben ist. Vielleicht war er irgendwo eingeklemmt und ist verhungert oder es war ihm zu kalt. Tja. Bis gestern nacht.

Ich machte meine übliche Runde, kam am Becken vorbei und bekam einen Mordsschreck: da trieb sich irgendein Riesenvieh im Vordergrund herum. Taschenlampe geholt, nachgeschaut und siehe da: der olle Knurrwels! Unfassbar. Ich frage mich echt, wie der die letzten Monate überlebt hat.

Eigenartig ist, dass er ausgerechnet jetzt aufgetaucht ist. Am Mittwoch habe ich nämlich das Becken umgebaut. Unter anderem habe ich auch eine Wurzel entfernt. Vielleicht war er darunter eingeklemmt und ich hab ihn befreit. Oder er hat so eine Art Winterschlaf gemacht und ich hab ihn geweckt. Wer weiss :)

Hier ist er also: mein Agamyxis pectinifrons, Alter unbekannt, Name Erwin:

Bild: Erwin 1
Erwin 1 (Feb. 21, 2014, 4:11 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 2
Erwin 2 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 3
Erwin 3 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 4
Erwin 4 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 5
Erwin 5 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 6
Erwin 6 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]
Bild: Erwin 7
Erwin 7 (Feb. 21, 2014, 4:12 p.m.)
[Tags: fische ] [Album: Aquarium ]

21.02.2014 16:11 CC0 Aquarium