There is definitely a need for being, or becoming more than careful with the fact that this here plugs directly into our brain. At least in our space here we have no algos and advertisement ads, to be more precise, sh** isn't even a word for that crap. Never the less, it is primordial to get away from the consideration that it's good education and being polite to follow or follow back. The profiles and hashtags, another very important source, we follow are our #newsAggregator, our #algorithm.
Time ago, a profile stated:
#exclaimer
This profile follows/unfollows quite randomly others, being them followers, leaders or … what ever.
The reasons/criteria might vary from time to time.
… in other words:
Don’t worry [at least try to] be happy …
Also there is the list feature to colapse or ignore content. Just crossed a extended one with the following:
Musk, Zuckerberg, Facebook, Meta, Twitter, Instagram, X, Trump, Melania, JD Vance, USpol, AfD, Weidel, Soeder, Merz, Spahn, Meloni, Von der Leyen, Putin, Orban, unsolicited advise
As of now it looks like that one works like charm.
Free Our Feeds and Algorithmic Pluralism
Today’s public square is on private property. To fight inequality, participate in democracy, and build an equitable society and economy, we must build a true public commons beyond one or two corporate-owned, profit-driven spaces.
With the open social web, the production, distribution and use of online content is being freed from the silos erected by today’s largest multinationals. But our data is still captured in AI systems that have “reached scale”– essentially the search, recommendation, and moderation algorithms that manipulate content consumption. These are monopoly technologies by their very design.
The detrimental consequences to society of this status quo are diverse and well-documented: concentration of profits and power, degraded information and media landscapes, prominence of polarizing content, disinformation and online harassment, degraded mental health, and more.
There is a broad vision for something different. We do not have to settle for how corporate spaces choose to govern, or not govern, themselves. The promise of an open social web is that we can all join communities and that online communities can be interconnected.
The Social Web Foundation focuses on the network of platforms connected via ActivityPub. We also support efforts to make other distributed social networking protocols more open and equitable. For this reason, we are excited to support the #FreeOurFeeds campaign launching today. This campaign is an opportunity to develop the capacity needed for the open social web protocols– ActivityPub along with Bluesky’s AT Protocol– to better interoperate, leveraging the entire open social ecosystem to create a working demonstration of algorithmic pluralism at scale.
We look forward to contributing to the essential work that follows from the campaign #FreeOurFeeds: Infrastructure, Innovation Ecosystem, and Governance.
Operating open and independent infrastructure services for social applications are essential but costly. Some proposed outcomes of #FreeOurFeeds are:
- Independent implementations of relays, bridges and native protocol interoperability
- Standardizing and testing intermediary functions like user authentication services
- Personalising and streamlining data transfer and backups across all services.
The #FreeOurFeeds seed funds can support an innovation ecosystem of public-interest alternatives. Just imagine the impact of third-party recommendations and moderation systems, LLM diversity, and curation, news and information discovery.
Open social web innovation in global governance spaces supports diverse, online communities. Protocols need to remain capture-resistant and supportive of open innovation and interoperability across the open social web and an industry-wide transition to interoperable protocols and public interest digital infrastructure is needed.
#FreeOurFeeds is a public crowdfunder to realize this vision with material support, but it is also an opportunity to create a powerful public narrative, bring experts together and plot a strategy around the need for investing in algorithmic pluralism and digital public infrastructures. I’m honored to join the “custodians” who are supporting the vision for this emerging work including Nabiha Syed, Kelsey Hightower, Robin Berjon, Deepti Doshi, Marc Faddoul and Sherif Elsayed-Ali. We hope you’ll join us by signing up at freeourfeeds.com.
What is the Fediverse?
The Fediverse, also known as the social web, is a network of independent social platforms connected by the open standard protocol ActivityPub. Users on a participating platform can follow their fri…Social Web Foundation
Welcome to the New Non-profit on the Fediverse
Mastodon today announced a new non-profit to manage the next steps for the project. From our perspective, this is a great sign of maturation in the social web software space. Best of luck to Eugen and team as they take this next step. We look forward to working with Mastodon towards a bigger, better Fediverse.
The people should own the town square
It is more important than ever that the social web is not controlled by corporations. Today, Mastodon is taking another step towards its founding ideals: independence and non-profit ownership.Mastodon Blog
teilten dies erneut
Daniela Pagenstecher 🇺🇦 🚴♂️ 📚 und why_o_why haben dies geteilt.
Riesa: Linke-Politiker Nguyen von Polizist verletzt
Riesa: Linke-Politiker Nguyen von Polizist verletzt
Der Linken-Abgeordnete des sächsischen Landtags, Nam Duy Nguyen, ist am Rande des AfD-Parteitags in Riesa von einem Polizisten geschlagen worden. Der Politiker verlor nach eigener Aussage kurz das Bewusstsein.Felix Huesmann (Leipziger Volkszeitung)
War früher als Landtagskandidat mit Bundes- und Landtagsabgeordneten tatsächlich diverse Male bei solchen Geschichten dabei, selbe Partei.(Bin aber nicht mehr Mitglied)
Feststellung:
1. Gefühlt 95% der Polizisten haben keine Ahnung was ein parlamentarischer Beobachter(PBO) ist. Das liegt aber auch an der sehr schwammigen Rechtslage in Deutschland - direkt definiert ist selbiger nämlich nicht.
2. Erklärt man es Ihnen wird sehr argwöhnisch nachgefragt welcher Partei man angehört, sobald raus kommt das es Grüne (selbst in BW!), Linke und sogar SPD auch gleich deutlich zu spüren,bis hin zu offenen Beleidigungen.
3. Die Polizeiführer wissen im Regelfall was ein parlamentarischer Beobachter ist und nutzen diese gelegentlich als Vermittler, ansonsten ist der Hass aber genauso groß.
4. De facto musst du rechtlich echt fit sein oder gleich einen Anwalt mitbringen. Denn es wird laufend versucht PBOs mit illegitimen Mitteln einzuschränken. Das geht von "sie dürfen sich nur in der Medienzone aufhalten" über absichtliches Abtrennen (hab schon erlebt,dass man extra Sprinter umparkte damit wir im Blick eingeschränkt waren) bis hin zu bewusstem Rechtsbruch wie die Ingewahrsamnahme, das Festhalten in Kesseln,etc.
5. Auch angesteuert kommt es immer wieder zu Problemen. Ich war tatsächlich mal mit einem der wenigen CDUler unterwegs die diese Möglichkeit nutzen - selbiger war geschockt wie oft "aus Versehen" Dosen in unsere Richtung getreten werden,wie oft man den wütenden Nazimob in diese Richtung durchbrechen lässt,etc.
6. Generell muss man sich keinen Schutz vor wütenden Faschos erhoffen-im Gegenteil,habe erlebt wie tlw. noch auf die Parteizugehörigkeit hingewiesen wurde.
Das soll übrigens nicht heißen,dass es nicht auch PBOs gibt die ihre Rolle einseitig ausleben und andere die bewusst provozieren. Die Institution muss aber viel klarer rechtlich definiert werden,denn sie ist wahnsinnig wichtig und va. von allen Parteien der Mitte genutzt werden.
Umgekehrt sind auch nicht alle Polizisten Arschlöcher. Von den 100 Mann die an dir vorbei ziehen sind 2 problematisch, der Rest nicht. Die beiden sind Arschlöcher,dienstlich wie privat aber es gibt (mehr) gute als diese.
Aber viel zu viele halfen die Klappe. Das ist das größte Problem.
G'sudert wird!
Mei Kühlschrank is eingangen. Zum glück is eh grod no koit gnua.
Und no wos: bei mir ums Eck ist eine verkehrsabhängige Ampel und in letzter Zeit kommt es soo häufig vor, dass da jemand so deppat steht dass die Ampel einfach nicht schaltet, bist du gscheit ist das nervig
Deppate Ampeln? Manchmal hab ich das Gefühl, die Ampeln in Linz hat a vierjähriger programmiert. Dass dann manche Autofahrer bei Dunkelgelb noch in die Kreuzung einfahren, obwohl eh in alle richtungen alles steht, hilft a ned.
Ich glaub, wenn die Linzer a bissl weniger blöd fahren würden, könnt der übliche Pendlerstau locker 20% kürzer sein.
Content Policy on the Social Web
On Monday, Mark Zuckerberg, CEO of Meta, announced a new content policy for Meta on Threads. We are disappointed in these changes, which put vulnerable people on and off Meta platforms in harm’s way for harassment. Ideas matter, and history shows that online misinformation and harassment can lead to violence in the real world. There are good analyses of the details of the policy changes at EFF, The Verge, and Platformer.
Meta is one of many ActivityPub implementers and a supporter of the Social Web Foundation. We strongly encourage Meta’s executive and content teams to come back in line with best practices of a zero harm social media ecosystem. Reconsidering this policy change would preserve the crucial distinction between political differences of opinion and dehumanizing harassment. The SWF is available to discuss Meta’s content moderation policies and processes to make them more humane and responsible.
Distributed Moderation
What do these changes mean for the Fediverse? Through ActivityPub, Meta’s Threads network is connected to the social web, also called the Fediverse. This is a diverse network of independent social services using different codebases and different kinds of content. The network of 300M users of Threads can follow and be followed by people in tens of thousands of other communities. These services are operated by a variety of entities: corporations, universities, enterprise IT, cooperatives, non-profit organizations, and self-organized volunteers.
Theoretically, this distributed structure allows people to make choices about which platforms they want to use – based not only on technical features, but also on community composition and moderation policies. Users don’t need to give up on social connections they already have with friends and family; they can stay connected across services using ActivityPub. Different communities and services can have different content policies, but people in different communities can still stay connected.
Ideally, having an account on a Fediverse service gives people the best of both worlds: they can stay connected to users and content they like, and filter out content and users that they don’t. When unwanted content from one community lands in the feeds of people in other communities, the receiving users or their moderators can react under their own local policy: removing individual text or image posts; blocking individual users; or blocking the entire sending community.
Practically, though, there are limitations to this flexibility. Filtering on the receiving side requires orders of magnitude more effort. If a single sending service delivers bad content to users on one hundred or one thousand receiving services, each moderator on the receiving end has to clean up the mess locally. Moderators get understandably frustrated with this kind of displacement of responsibility. A common response is to block servers that send bad content entirely.
In the case of Threads, though, there are complicating factors. Threads is much, much bigger than the typical Fediverse community, and it has many high-profile users in politics, media and technology. It’s also an easy onboarding service to the Fediverse for people who are used to Facebook or Instagram, meaning many of our friends, colleagues and family use it. Blocking the Threads service means blocking access for all users on the receiving service from all these important accounts.
Unfortunately, there’s not an easy answer for Fediverse moderators. We encourage trust and safety teams across the social web to use their best judgement and the tools available to keep users safe, connected, and informed, and also to minimize moderators’ stress and burnout. IFTAS Connect is a great community resource for connecting with other moderators to discuss these tradeoffs.
Improving Social Web Resilience
We see the challenge of a large service that has poor local content policy as a chance to strengthen the social and technical infrastructure of the Fediverse. None of these options will resolve current problems immediately, but we hope starting the research now will make the Fediverse more resilient in the future.
- Finer-grained filtering tools. As mentioned above, moderators on the Fediverse can automatically filter content by author or by originating service. Some platforms also let moderators filter by keywords – for example, blocking out racist or homophobic slurs. More difficult forms of filtering, such as detecting unacceptable images, or the subtle meaning of text, requires more sophisticated algorithmic filtering not supported by many Fediverse platforms. Balancing the ease of use of this kind of filter with the desire from many communities to have final control by human moderators is a good area for future research.
- Collaborative moderation tools. Email filtering systems re-use signals received from other users, so that if a message is marked as spam by one user, or a few users, other users will never see the message. This can balance the desire for human moderation with a significantly lowered total effort for moderators. Shared server blocklists are somewhat common on the Fediverse, but deeper per-user and per-post collaborative filtering is not. Balancing, once again, the specific priorities of a given community with the advantage of collaborative filtering would also require further research.
- Fact-checking and community notes. One major part of the Meta announcement was a cancellation of the fact-checking program for posts on Meta, and its replacement with a community notes feature, which defers fact-checking to volunteers. Neither of these features (professional and volunteer fact-checking) are supported directly in ActivityPub. We think there’s a place for a variety of fact-checking services on the Fediverse, providing annotations on Fediverse content without requiring permissions from the author, the sending service, or even the receiving service. Building the protocol features and reference implementations, as well as encouraging the participation of fact-checking services, is a good next step in this area.
- Jurisdictional boundaries. Zuckerberg mentions in his update that Meta will be collaborating with the US government to resist demands for content policy changes by other governments. Regardless of the valence of these content policy demands, this question highlights an important feature of the Fediverse, namely, that federated services can operate within specific jurisdictions and conform with their regulations. Content that is conveyed across legal boundaries between services can be more clearly filtered or blocked to comply with local rules. We encourage national and regional governments to further investigate this structure for social networking and global connectivity.
- Data portability. Choosing a social media platform to use is an important freedom in the social web. The Fediverse supports limited data portability, such that users can move their followers and followed accounts to a new server almost seamlessly. However, this move leaves all posted content, like text and images, on the old server, as well as metadata such as likes and shares. The new LOLA protocol would allow a full move between servers. We want to see more work on implementing LOLA in Fediverse platforms.
Ultimately, the safety and well-being of people around the world should not be in the hands of any single company. Moderation policies are a competitive advantage in an open social network. We continue to encourage the use of ActivityPub, and the distributed control that it brings.
Meta surrenders to the right on speech
“I really think this a precursor for genocide,” a former employee tells PlatformerCasey Newton (Platformer)
Also Christine Lemmer-Webber, co-creator of the ActivityPub protocol:
„Is it time for an Isolate Threads campaign
Get the fuck outta here Mark Muskerberg get the FUCK OUT“
ff. [full ack]
digitalcourage.social/@cwebber…
Is it time for an Isolate Threads campaign
Sebastian Lasse hat dies geteilt.
PS
cause war criminals need more masculine energy
„Meta Deletes Trans and Nonbinary Messenger Themes“
404media.co/meta-deletes-trans…
Meta Deletes Trans and Nonbinary Messenger Themes
Amid a series of changes that allows users to target LGBTQ+ people, Meta has deleted product features it initially championed.Jason Koebler (404 Media)
^ Alerta.
It comes to our attention that #Facebook starts censoring pixelfed links :
digitalcourage.social/@stpop@s…
#meta #instagram #threads vs #pixelfed
#FckMeta hat Schiss."Beispiellos" gewachsen: Facebook sperrt Links zu Instagram-Alternative Pixelfed" weiss @heiseonline
Unseren Popcast findet ihr nu hier:
>> pixelfed.social/stpauli oder folgt @stpauliMeine eigene Instanz findet ihr hier >> px.ring2.de
#fcsp #meta #instagram #fuckzuck #pixelfed #fediverse
teilten dies erneut
Sebastian Lasse, Überlebenskünstler (er/ihm) und FriedaFray haben dies geteilt.
update
Meta Facebook Insta censoring the fedi is a reproducible bug:
digitalcourage.social/@Prucker…
Definiere reproduzierbar ...
Update:
Meanwhile covered in german lead media:
[DE] heise.de/news/Beispiellos-gewa…
I will propose a meeting to the Policy SIG.
Esteemed #Fediverse
we will inform the EU Commission about #Facebook censoring links to #pixelfed.
When Musk did the same with mastodon links, we provided the EU with a huge example set, so if you are on Facebook/Instagram or any and links to fedi endpoints are censored, please provide us with a screenshot, link address and the reason as screenshot.
"Beispiellos" gewachsen: Facebook sperrt Links zu Instagram-Alternative Pixelfed
Seit Metas Ankündigung, Inhalte auf den eigenen Portalen anders zu moderieren, wächst Pixelfed stark. Nun ist aufgefallen, dass Facebook Links dorthin sperrt.Martin Holland (heise online)
teilten dies erneut
Sebastian Lasse, aiquez und Irrelefant haben dies geteilt.
Update
Meanwhile covered in @404mediaco too
404media.co/meta-is-blocking-l…
Please note that the Policy SIGs task is to collect it and forward it to the EU for a DMA complaint and other procedures.
@swf
Meta Is Blocking Links to Decentralized Instagram Competitor Pixelfed
Pixelfed said it is "seeing unprecedented levels of traffic."Jason Koebler (404 Media)
Number Of Meat-Free Care Home Residents Could Double By 2031, Says Research
Number Of Meat-Free Care Home Residents Could Double By 2031, Says Research
The number of vegan and vegetarian care home residents in the UK will continue climbing over the next five years, according to new researchLiam Pritchett (Plant Based News)
Voting on the PieFed roadmap for 2025 is now open!
We've brainstormed a few ideas for where we could focus our development efforts this year and created a post in a community for each idea.
This is the community: !piefed_2025@piefed.social
Now it's up to you to vote on each post to influence the priorities of those ideas! Please upvote those ideas that are important to you, ignore those that do not and only downvote when an idea seems like a counter-productive waste of time and energy.
Vote for as many ideas as you like but be selective. Something like upvote your top 10 ideas and downvote the bottom 5, that kind of thing.
@howTo get rid of #google on your #android phone with @free open source software.
This is the site where you get the #playstore replacement by @F-Droid for your phone:
f-droid.org
There is an emulator for the google #APP store that let's you download APP's without register to google at all on #f-droid.
f-droid.org/en/packages/com.au…
There are also sites where you get APP's that are on google play, for example:
apkpure.com/
You can reset any android phone, start from scratch, confirm the inicial TOS but not register with google services and the playstore. That's the moment when you get a little bit sealioned with the intention to trick you into confirm registering with google and perhaps the phone vendor and maybe the producer.
In the android aplication settings in applications you can stop and uninstall all standard google programs, including things like #chrome. The only one I use is #googleMaps, but I don't allow access to the #GPS, for any APP, including weather forecast. And I have GPS nearly always turned off.
They might sealion you into registering with google to update things like chrome so stopping those APP's is useful.
You wont have a #gmail account or anything but you normally have some kind of browser, or the #USB connection for the #phone. From there you start by installing the f-droid APP, you have to allow third party APP's and can install the rest from there. You probably would want to install #KDEconnect, #Newpipe or #Pipepipe as YT replacement, #mastodon or #fedilab APP for the #fediVerse, of course there are more options, #lightning as web browser, #antennaPod for podcasts and some email client.
Updates for f-droid installed APP's come in automatically and you have to allow each and every one. Of course the android updates themself work as always.
2025 – 012: Anders
Wie ich mich über mich selbst wundere.
Nachdem mir gestern diese Figur unterkam, passierte heute am Schreibplatz das nächste „Wunder”.
Feder und Tinte (und für spezielle Zwecke ein Vierfarbkugelschreiber) sind seit vielen Jahren meine üblichen Schreibwerkzeuge […]
#Bleistift #Buchstaben #Ideen #Normal #Schreiben #Staunen #Suchen
deremil.blogda.ch/2025/01/12/0…
2025 – 012: Anders
Wie ich mich über mich selbst wundere. Nachdem mir gestern diese Figur unterkam, passierte heute am Schreibplatz das nächste „Wunder”. Feder und Tinte (und für spezielle Zwecke ein Vierfarbkugelsch…GeDACHt | Geschrieben | Erlebt | Gesehen
Zigbee Device Reviews
When I first started setting up my home automation, I decided on Zigbee, and I very much dove in head-first. I set up dozens of Zigbee devices, and some worked a lot better than others. I have a fairly stable Zigbee network with well over 100 devices, but many of those have been replaced over time. To save others the wasted time and money, I wanted to give a short breakdown of what I've noticed across brands.
- SONOFF: My Zigbee controller is made by SONOFF, and it works well. As far as their motion sensors, not so much (I even made a post about how bad they were about a year ago). Their motion sensors give such unreliable results that they're borderline useless. Their plugs work generally okay, although they do drop off my network occasionally. Overall, they really wouldn't be my first choice.
- Aquara: They make some very slick-looking devices, but they're horrible. Magnetic door sensors frequently just get stuck in an open or closed state, or just drop off the network completely. I used two of their leak sensors. One is still working well; the other just spontaneously decided to stop responding completely. I have a few of their pushbuttons; it took me at least a dozen tries to pair them, but they seem to work well after that. Overall, Aquara devices either quit responding or drop off the network more frequently than any other brand; I will never buy another Aquara device.
- DOGAIN: I bought several of their plugs. So far, not a single issue. I assume they're a white-label brand, so I don't know who actually makes the hardware, but I have no complaints so far.
- MHCOZY: Another white-label brand. I've purchased several of their relay switches. I haven't had a single problem with any of them, and I'm using quite a few.
- Haozee: Probably another white-label brand. I have several of their mmWave sensors. Occasionally they get stuck in a "detected" state, but rarely. They have never dropped off my network. I'd buy more.
- Phillips (Hue): They're exceptionally expensive, but for a reason. I have a lot of their smart bulbs, and a few outdoor motion sensors. They all work flawlessly. Don't use the Hue app or a Hue bridge, though, unless you want to be locked into their app; just pair your device with a third-party Zigbee controller.
- Leviton: I have replaced every single in-wall switch in my home with a Leviton smart switch or smart dimmer. They're a well-known brand, so I would expect their products to work well, and they do. My only complaint is that occasionally one of the switches will drop and refuse to communicate unless I power it off (with a breaker); this is rare, though, and normally corresponds with a power outage.
- Thirdreality: I saved Thirdreality for last because I have absolutely no complaints at all. They are my go-to for Zigbee devices. I have many of their temperature sensors, plugs, magnetic door sensors, motion sensors, soil moisture sensors, etc. I have never had a device drop off my network or stop working correctly. I have dozens of their devices, and my only issue was a climate sensor that got stuck at 99% humidity after I accidentally sprayed water into the case. That's my fault.
So, in general, if I was to re-build my Zigbee network from the ground up, I'd go for Thirdreality devices first. If they didn't make what I need, I'd go for Phillips Hue, and if I still couldn't find what I need, then that's what the list above is for.
I'm hoping to see some replies to this; what are your experiences with different Zigbee devices? Any brands you either trust or would never buy from?
Edit: As others have mentioned, your Zigbee integration (also also possibly your controller) may make a difference in reliability. I am using ZHA and a SONOFF controller. Your experience may be different.
I have to say, I have dozens upon dozens* of generic "Tuya" ZigBee devices from Ali, and they all work flawlessly. The only ones I have issues with is a couple of GU10 bulbs that the devs decided should be routers when bulbs really shouldn't route since they can be turned off at the switch. I really wished there was a way to prevent that.
*96 total devices in Z2M, a handful are Sinopé mains voltage thermostats for baseboard heaters (great units absolutely recommend!), another 3 are inovelli switches (again no issues here, great stuff), a dozen are Aqara (I've seen the hate but tbh I never noticed any issues). Almost everything else is Moes/Tuya. I even have a generic tuya temperature/humidity sensor that has been outside for a year and a half in the harsh Canadian climate (from -30C to 30C).
I will say, I have a couple of AIQ and mmWave sensors and I don't like them because they produce a LOT of data and kind of spam the network, if I replace them I'll do WiFi for those.
I run a HamGeek POE Coordinator.
Epson ET-2815 on Linux - epson-printer-utility not recognizing the printer
After a fairly hassle-free year or so with this Epson ET-2815 printer, the cyan now won't print at all (no lines, no nothing - printing a full cyan page just yields white). I believe the print head is fully clogged and I want to perform a print head cleaning. I need the epson-printer-utility
to do so (available from here, manual here), which I did not set up when I initially set up the printer.
I have installed epson-printer-utility
as instructed and run it through the terminal, but I am met with a error message saying "The printer was not found". The printer is otherwise found on the network and configured in CUPS, and I can print just fine with it (up until the cyan channel now doesn't work anymore).
I ran across this old post suggesting that the udev-rule is copied over to /etc/udev/rules.d
, but the installation process seems to have taken care of that already.
This print head function is also available through this god-awful mobile app that I had to use to set it up, but now the app also cannot find the printer, even though I try to connect directly to the IP. I have ensured that my phone is on the same network as the printer, but alas.
This happened straight after I set up the integration in Home Assistant, but I imagine this is just a coincidence. I last used the printer just over a month ago.
Anyone have any experience dealing with this?
epson-printer-utility
Hi! I used this trick to run epson-printer-utility and followed some instructions from Epson site . But... Epson-printer-utility says "Thewww.linuxquestions.org
🌠Richard Limbert ist Musiker, Komponist und Songwriter aus dem Rheinland 🐊 mit Basis in Leipzig. In seinen eigenen, anekdotische Liedern mit thematischen Schwerpunkten in Geschichte und Kultur erkennt man die Handschrift eines wahren Folkloristen. Der großen Leidenschaft in der Musikforschung geht er dabei nach, indem er sich oft und gerne in die Repertoires US amerikanischer Folk Traditionen bewegt. Ein Musiker, den es so selten gibt. - 📰 " Tief getränkt im Blues sind seine Songs komponiert, eine gute Prise Folk und Rock würzen die Mischung – wer genau hinhört, erkennt eine Menge Bob Dylan in Richard Limbert. " - Leipziger Volkszeitung
🌟🌟🌟
💫 Wenn die Schneeflocken [...] ihre letzten Runden über den Alleen drehen und die Prinzessinnen des Vorfrühlings 🦄 über die Vorstadthäuser steigen, bringt Torsten Torsten mit leichtem Swing, duften Melodien und klugen Texten den Abend zum Funkeln. Der Leipziger Singersongwriter groovt sich mit der Gitarre durch die wilden Vorgärten der deutschen Melancholie und erweckt mit seinen cleveren Lyrics eine heitere Untergrundwelt zum Leben. Deren Zauber-Zentrale ist irgendwo zwischen Apachenboulevard, Baumhaus und Stadtpark zu suchen. Seine meist deutschsprachigen Lieder begleitet er mit ausgesuchten Jazz- und Britpop-Akkorden, gelegentlich auch Hackbrett, Santur oder Duduk und bringt einen Touch von Swing auf die Bühne. - 📻 "Absolute Hörempfehlung" - Marius Magaard ByteFM
Look at my horse
Lesedauer < 1 Minute
My horse is amazing. Kennen wir alle noch. Oder auch nicht, wenn du zu jung bist. Ich glaube, das Internet braucht alle paar Jahre ein Pferdelied. Die Band OCP (On Company Time) hat die neue Pferdehymne abgeliefert.
youtube.com/watch?v=6v_R180kIG…
#OCP #OnCompanyTime #Pferdelied
HALF HORSE HALF MAN | OFFICIAL VIDEO
#epicmusic #comedymusic #music #eurovision Merch: https://octmusic.myshopify.com/Pre-save Half Horse Half Man: https://distrokid.com/hyperfollow/oct2/half-ho...YouTube
teilten dies erneut
tomate 🍅 hat dies geteilt.
Jascha wrapped 2024
Lesedauer 3 Minuten
Veröffentlichungen 2024
Auf meinem Blog habe ich im Jahr 18 Beiträge veröffentlicht.
An einem Abend im Februar schrieb ich 13 Gedichte auf A6 Karten. Da ich eine Sauklaue schwer zu lesende Handschrift habe, habe ich sie nochmal abgetippt und zusammen mit Scans der Originale in einem kleinen Band veröffentlicht. Erschienen ist der Band am 28.02.2024 im Selfpublishing. Hier findest Du alle Infos.
Ich habe den Lyrikband Trans-Millenial Daydream von Alfi zusammen mit Marek Gross übersetzt. Er ist zweisprachig im Ach je Verlag erschienen. Gibt es direkt im Verlagsshop und den Buchhändler*innen deines Vertrauens.
Der Fragebogen
Zugenommen oder abgenommen?
Januar, Februar, März: viel zu viel abgenommen.
April und Juni wieder auf das vorherige Gewicht zurück, den Rest des Jahres habe ich mein Gewicht gehalten.
Wie gut hat das Jahresthema funktioniert?
Dieses Jahr war mein großes Thema „Gesundheit“. Ohne dieses Thema hätte ich vermutlich mein Herzproblem erst viel z spät behandeln lassen. So konnte mein Problem – eine koronare Herzkrankheit – – mit einem einfachen Herzkatheter eingegrenzt und mit Hilfe eine Stents gelöst werden. Mehr Infos über das Setzen und die Wirkung von Stents gibt es hier.
Haare länger oder kürzer?
Anders – keine Ahnung ob das als länger oder kürzer durch geht. Ich glaube insgesamt ein wenig länger, sind aber nach wie vor kurz.
Kurzsichtiger oder weitsichtiger?
Letztes Jahr hatte ich ja endlich Kontaktlinsen und was ist passiert? Ich habe nun eine Lesebrille, die ich verwende, wenn ich die Linsen trage. Meine Augen werden wohl alt und ich werde mich in 2025 um Gleitsichtlinsen bemühen.
Mehr Kohle oder weniger?
Dank meines Jobs bei modzero mehr als letztes Jahr.
Mehr ausgegeben oder weniger?
Ich habe weniger ausgegeben,
Mehr bewegt oder weniger?
Alleine dass ich jeden Tag ins Büro gehen sorgt für mehr Bewegung bei mir. Das ist gut.
Der hirnrissigste Plan?
Mich für eine Weiterbildung anzumelden.
Die gefährlichste Unternehmung?
2024 war, wie auch schon 2023, komplett ohne gefährliche Unternehmungen.
Die teuerste Anschaffung?
Ein neues MacBook Air.
Das beeindruckendste Buch?
Wie immer zu wenig gelesen und es hat mich auch einfach nix so wirklich beeindruckt.
Der ergreifendste Film?
Ich fand leider keinen Film ergreifend, den ich in dem Jahr gesehen habe. Ic hab e aber auch wenig Filme gesehen.
Die beste CD/das beste Album für 2024?
Die beste CD in 2024 und AUS 2024 war von JANUS die EP „All die Geister“. Gibt es direkt bei der Band im Knochenhaus oder bei Bandcamp.
youtube.com/watch?v=PEIbAbqFI3…
Ebenfalls ganz oben mit bei ist RIGs Soloalbum „Wurm“.
youtube.com/watch?v=pFrVLKRLx8…
Das schönste Konzert?
Ich war schon wieder bei JANUS auf dem Jahresabschlusskonzert – aber(!) das schönste Konzert war auf dem #38C3 am 29.12. der Auftritt von Die Helm & Der Weller im zweiten Stock am Spätverkauf.
Die meiste Zeit verbracht mit …?
Wie letztes Jahr auch: mit ~ihm~ und Gerhard am Telefon.
Die schönste Zeit verbracht mit …?
Mit ~ihm~ war es generell schön und am schönsten war es, als er mich einen Tag auf dem #38C3 besucht hat. Das war für mich ganz besonders.
Vorherrschendes Gefühl 2024?
die ersten 2⁄3 des Jahres Zufriedenheit und Liebe, dann Herzschmerz und Leere, jetzt zaghafte Zuversicht auf die Zukunft.
2024 zum ersten Mal getan?
Ich habe einen Genossenschaftsanteil erworben. Ich bin Miteigentümer vom nd.
2024 nach langer Zeit wieder getan?
Unbeschwert gelacht.
Drei Dinge, auf die ich gut hätte verzichten können?
Den generellen Zustand der Welt.
Die ganzen Steigbügelhalter des Faschismus,
Viel zu viel Physiotherapie.
Die wichtigste Sache, von der ich jemanden überzeugen wollte?
Ich hatte dieses Jahr kein Thema, von dem ich jemanden unbedingt überzeugen wollte. Erst hatte ich anderes zu tun, dann war ich zu sehr von mir selbst abgelenkt.
Das schönste Geschenk, das mir jemand gemacht hat?
Diese Bilder. Sie hängen gerade, ich stehe nur schief und bin zu faul, ein neues Bild zu machen.
2024 war mit einem Wort …?
Aushaltbar.
Titelbild: 2024 PNGs von Vecteezy
Jascha wrapped 2022
2022 ist nun fast zu Ende und ich habe mir ein bisschen Zeit genommen, über das Jahr nachzudenken.jascha.wtf
13 Gedichte
Lesedauer 2 Minuten13 kurze Gedichte, an einem Abend ausgekotzt und hingerotzt. Durchgestrichen, ergänzt, verschrieben und korrigiert.
Bring mich bitte gleich an die Stelle wo steht, wie ich den Band bekommen kann.
Update: 13 jetzt auch elektronisch erhältlich.
In der Nacht von dem 13. auf den 14. Februar 2023 ging es mir emotional nicht ganz so gut. Ich versuchte, meine Gedanken zu ordnen und nahm das nächstbeste, was ich zum Aufschreiben da hatte: blanko A6 Karten. Ich schrieb also auf, versuchte zu verarbeiten und irgendwie zu greifen, was mich nicht in Ruhe lässt.
Am nächsten Tag schaute ich mir die Karten an und schrieb die Texte am Rechner nochmal ab. Ich versuchte zu verstehen, was in meinem Kopf beim schreiben vor sich ging, warum ich um welche Buchstaben oder Wörter gerungen habe. Jedes mal, wenn ich mir die Karten anschaue und den fertigen durchaus immer noch rohen Text lese, komme ich auf ein anderes Ergebnis. Das finde ich spannend.
Aber was mache ich denn jetzt mit diesen 13 Texten? Was würde ihnen gerecht werden? Muss ich überhaupt etwas damit machen? Ja, muss ich. Ich setzte mich hin und überlegte und ich schaute auf den Stapel Karten mit der Original Handschrift und auf den Stapel der abgetippten Texte nebeneinander liegend.
Ich scannte die Originale ein, öffnete mein Grafikprogramm und ein wenig später war das PDF des Buchblocks fertig. Texte sortieren, in eine Reihenfolge bringen und… und was? Was nun? Als Download bereit stellen? Das wäre eine Möglichkeit, die ich aber diesmal nicht ergreifen wollte. Ich wollte etwas anderes: Die Texte so erleben, wie ich sie gerade erlebe – nebeneinander.
Der kleine Band enthält 30 Seiten, ist auf reinweißem Munken-Papier gedruckt, der Umschlag hat eine Softtouch-Kaschierung und es gibt den Band nicht im Laden oder online zu kaufen. Wenn Du ein Exemplar haben möchtest, gehst du wie folgt vor:
- Schreibe auf einen Briefumschlag Deine Adresse und klebe eine Briefmarke für einen Kompaktbrief drauf
- Packe diesen Umschlag in einen weiteren Briefumschlag (kann gefaltet werden) und klebe ihn zu.
- Adressiere diesen Umschlag an:
Jascha Ezra Urbach
Braunschweiger Str. 15
12055 Berlin- Klebe genug Porto drauf, so dass der Brief bei mir ankommt.
- Wirf den Umschlag in einen Briefkasten der Deutschen Post.
- Wenn Du nicht in Deutschland lebst, aber trotzdem ein Exemplar möchtest, schreibe mir eine Email.
Es sind noch 0 von 100 Exemplaren verfügbar.
Sobald ich einen Umschlag bekomme, packe ich ein Exemplar in den Umschlag und werfe ihn in den nächsten Briefkasten, so dass es das kleine Büchlein alsbald bei Dir ankommt.
Wenn wir uns irgendwo zufällig treffen und ich habe ein Exemplar dabei, bekommst du es auch einfach so von mir, dann kannst du dir den Briefumschlag sparen.
Und was ist, wenn du das Bändchen elektronisch haben willst? Dann kannst du entweder ein wundervolles PDF bei Xinxii oder Lulu erwerben oder ein unschönes Format für den Kindle bei Amazon. Weil das konvertierte Buch zu groß ist für 0,99 EUR musste ich den Preis auf 1,99 EUR setzen. Aber ihr sollt ja eh das gedruckte nehmen und nicht die elektronische Fassung.
13 findest Du auch auf BookWyrm und goodreads sowie in der Deutschen Nationalbibliothek, Der Zentralen Landesbibliothek Berlin, Open Library, auf inventaire und Library Thing.
Kontakt & Social Media
Um mich zu kontaktieren kannst du einen dieser Wege versuchen: E-Mail: jascha [AT] jascha.wtf ([AT] durch @ ersetzen - aber das wisst ihr ja)Mein GPG-Key: 1C283F8B92D0F9BB149B7360A43A844B114F9B08 (Direktdownload/Keyserver) Signal: Ein Kli…jascha.wtf
teilten dies erneut
tomate 🍅 hat dies geteilt.
NodeBB and Threads
There have been some reports (@bh4-tech I believe?) that NodeBB does not successfully federate with Threads. Looking into the issue, I discovered that it is only this domain community.nodebb.org
that is unable to get/send activites with Threads.net.
After some help from @erincandescent@akko.erincandescent.net @jaz@mastodon.iftas.org and @grishka@friends.grishka.me, I have discovered that our domain has been blocked by Threads for not serving up a public feed.
This is the feed they're specifically looking for. If your application does not serve it, it will be automatically blocked at some point. There is an appeal form you can fill out so your server can be re-instated.
- At this time, Threads seems to see the lack of the public feed as a non-starter for AP federation.
- As an AP software implementor, in order for admins running NodeBB to not have their servers auto-blocked, I will have to implement this API
- Threads relying on the existence of a Mastodon-specific API suggests that they're federating with Mastodon only (perhaps as part of a limited experiment), or that it is an oversight that needs to be fixed on their end with time.
Therefore if you wish for your NodeBB to federate with Threads, my guidance at this time is to whitelist your domain with Threads directly by filling out the form.
Threads • Log in
Join Threads to share ideas, ask questions, post random thoughts, find your people and more. Log in with your Instagram.Threads
‘It’s Total Chaos Internally at Meta Right Now’: Employees Protest Zuckerberg’s Anti LGBTQ Changes
‘It’s Total Chaos Internally at Meta Right Now’: Employees Protest Zuckerberg’s Anti LGBTQ Changes
Meta's decision to specifically allow users to call LGBTQ+ people "mentally ill" has sparked widespread backlash at the company.Jason Koebler (404 Media)
Afeela 1: Wenn Sony und Honda ein Auto bauen, kommt das dabei raus
Afeela 1: Wenn Sony und Honda ein Auto bauen, kommt das dabei raus
Der elektrische Afeela 1 von Sony Honda Mobility kostet ab 90.000 US-Dollar und wird in zwei Varianten ab Mitte 2026 in den USA angeboten.Nicolas La Rocco (ComputerBase)
cron mag das.
800 TOPS Computing-Performance stellt Afeela in Aussicht, um die Rohdaten von 18 Kameras, 1 LiDAR, 9 Radaren und 12 Ultraschallsensoren auszuwerten
Schon erstaunlich, wie viel Hardware die verbauen, und doch kann das Auto damit nicht besser fahren als der durchschnittliche Autofahrer.
2025 – 011: Ungewohnt
Ob die Figur dazu dient, mich mit mir selbst zu beschäftigen?
Ich klappe das Buch zu. Ein bißchen verärgert, aber nicht wütend. Aber so, wie das Leben darin beschrieben wird […]
#Anders #Buch #Erfahrung #Fiktion #Geschichte #Leben #Phantasie #Vermutung #Wissenschaft
deremil.blogda.ch/2025/01/11/0…
2025 – 011: Ungewohnt
Ob die Figur dazu dient, mich mit mir selbst zu beschäftigen? Ich klappe das Buch zu. Ein bißchen verärgert, aber nicht wütend. Aber so, wie das Leben darin beschrieben wird […]GeDACHt | Geschrieben | Erlebt | Gesehen
#friendica @Tutorial @forum.friendi.ca
Here some help for editing bbCode text colors with friendica.
In the spoilers you'll find lot's of colors, their codes and also their human readable code names.
Actually this is some information I couldn't find in the friendica /help pages, only the example with the color red.
Maybe something we could add to those pages?
Color name | Test Text |ALBHABETICAL order
Antiquewhite | Test text || Aqua | Test text || Aquamarine | Test text || Azure | Test text || Beige | Test text || Bisque | Test text || Blanchedalmond | Test text || Blue | Test text || Blueviolet | Test text || Brown | Test text || Burlywood | Test text || Cadetblue | Test text || Chartreuse | Test text || Chocolate | Test text || Coral | Test text || Cornflowerblue | Test text || Cornsilk | Test text || Crimson | Test text || Cyan | Test text || Darkblue | Test text || Darkcyan | Test text || Darkgoldenrod | Test text || Darkgray | Test text || Darkgreen | Test text || Darkkhaki | Test text || Darkmagenta | Test text || Darkolivegreen | Test text || Darkorange | Test text || Darkorchid | Test text || Darkred | Test text || Darksalmon | Test text || Darkseagreen | Test text || Darkslateblue | Test text || Darkslategray | Test text || Darkturquoise | Test text || Darkviolet | Test text || Deeppink | Test text || Deepskyblue | Test text || Dimgray | Test text || Dodgerblue | Test text || Firebrick | Test text || Floralwhite | Test text || Forestgreen | Test text || Fuchsia | Test text || Gainsboro | Test text || Ghostwhite | Test text || Gold | Test text || Goldenrod | Test text || Gray | Test text || Green | Test text || Greenyellow | Test text || Honeydew | Test text || Hotpink | Test text || Indianred | Test text || Indigo | Test text || Ivory | Test text || Khaki | Test text || Lavender | Test text || Lavenderblush | Test text || Lawngreen | Test text || Lemonchiffon | Test text || Lightblue | Test text || Lightcoral | Test text || Lightcyan | Test text || Lightgoldenrodyellow | Test text || Lightgreen | Test text || Lightgrey | Test text || Lightpink | Test text || Lightsalmon | Test text || Lightseagreen | Test text || Lightskyblue | Test text || Lightslategray | Test text || Lightsteelblue | ]Test text || Linen | Test text || Magenta | Test text || Maroon | Test text || Mediumaquamarine | Test text || Mediumblue | Test text || Mediumorchid | Test text || Mediumpurple | Test text || Mediumseagreen | Test text || Mediumslateblue | Test text || Mediumspringgreen | Test text || Mediumturquoise | Test text || Mediumvioletred | Test text || Midnightblue | Test text || Mintcream | Test text || Mistyrose | Test text || Moccasin | Test text || Navajowhite | Test text || Navy | Test text || Oldlace | Test text || Olive | Test text || Olivedrab | Test text || Orange | Test text || Orangered | Test text || Orchid | Test text || Palegoldenrod | Test text || Palegreen | Test text || Paleturquoise | Test text || Palevioletred | Test text || Papayawhip | Test text || Peachpuff | Test text || Peru | Test text || Pink | Test text || Plum | Test text || Powderblue | Test text || Purple | Test text || Red | Test text || Rosybrown | Test text || Royalblue | Test text || Saddlebrown | Test text || Salmon | Test text || Sandybrown | Test text || Seagreen | Test text || Seashell | Test text || Sienna | Test text || Silver | Test text || Skyblue | Test text || Slateblue | Test text || Slategray | Test text || Snow | Test text || Springgreen | Test text || Steelblue | Test text || Tan | Test text || Teal | Test text || Thistle | Test text || Tomato | Test text || Turquoise | Test text || Violet | Test text || Wheat | Test text || White | Test text || Whitesmoke | Test text || Yellow | Test text || Yellowgreen | Test textColor name | Test Text | order BY COLOR
Pink | Test text || Lightpink | Test text || Hotpink | Test text || Deeppink | Test text || Palevioletred | Test text || Mediumvioletred | Test text || Lavender | Test text || Thistle | Test text || Plum | Test text || Orchid | Test text || Violet | Test text || Fuchsia | Test text || Magenta | Test text || Mediumorchid | Test text || Darkorchid | Test text || Darkviolet | Test text || Blueviolet | Test text || Darkmagenta | Test text || Purple | Test text || Mediumpurple | Test text || Mediumslateblue | Test text || Slateblue | Test text || Darkslateblue | Test text || Rebeccapurple | Test text || Indigo | Test text || Lightsalmon | Test text || Salmon | Test text || Darksalmon | Test text || Lightcoral | Test text || Indianred | Test text || Crimson | Test text || Red | Test text || Firebrick | Test text || Darkred | Test text || Maroon | Test text || Orange | Test text || Darkorange | Test text || Coral | Test text || Tomato | Test text || Orangered | Test text || Gold | Test text || Yellow | Test text || Lightyellow | Test text || Lemonchiffon | Test text || Lightgoldenrodyellow | Test text || Papayawhip | Test text || Moccasin | Test text || Peachpuff | Test text || Palegoldenrod | Test text || Khaki | Test text || Darkkhaki | Test text || Goldenrod | Test text || Darkgoldenrod | Test text || Greenyellow | Test text || Chartreuse | Test text || Lawngreen | Test text || Lime | Test text || Limegreen | Test text || Palegreen | Test text || Lightgreen | Test text || Mediumspringgreen | Test text || Springgreen | Test text || Mediumseagreen | Test text || Seagreen | Test text || Forestgreen | Test text || Green | Test text || Darkgreen | Test text || Yellowgreen | Test text || Olivedrab | Test text || Olive | Test text || Darkolivegreen | Test text || Mediumaquamarine | Test text || Darkseagreen | Test text || Lightseagreen | Test text || Darkcyan | Test text || Teal | Test text || Aqua | Test text || Cyan | Test text || Lightcyan | Test text || Paleturquoise | Test text || Aquamarine | Test text || Turquoise | Test text || Mediumturquoise | Test text || Darkturquoise | Test text || Cadetblue | Test text || Steelblue | Test text || Lightsteelblue | Test text || Lightblue | Test text || Powderblue | Test text || Lightskyblue | Test text || Skyblue | Test text || Cornflowerblue | Test text || Deepskyblue | Test text || Dodgerblue | Test text || Royalblue | Test text || Blue | Test text || Mediumblue | Test text || Darkblue | Test text || Navy | Test text || Midnightblue | Test textColor code in respective color | ALBABETICAL order
FAEBD7 || 00FFFF || 7FFFD4 || F0FFFF || F5F5DC || FFE4C4 || FFEBCD || 0000FF || 8A2BE2 || A52A2A || DEB887 || 5F9EA0 || 7FFF00 || D2691E || FF7F50 || 6495ED || FFF8DC || DC143C || 00FFFF || 00008B || 008B8B || B8860B || A9A9A9 || 006400 || BDB76B || 8B008B || 556B2F || FF8C00 || 9932CC || 8B0000 || E9967A || 8FBC8F || 483D8B || 2F4F4F || 00CED1 || 9400D3 || FF1493 || 00BFFF || 696969 || 1E90FF || B22222 || FFFAF0 || 228B22 || FF00FF || DCDCDC || F8F8FF || FFD700 || DAA520 || 808080 || 008000 || ADFF2F || F0FFF0 || FF69B4 || CD5C5C || 4B0082 || FFFFF0 || F0E68C || E6E6FA || FFF0F5 || 7CFC00 || FFFACD || ADD8E6 || F08080 || E0FFFF || FAFAD2 || 90EE90 || D3D3D3 || FFB6C1 || FFA07A || 20B2AA || 87CEFA || 778899 || B0C4DE] || FAF0E6 || FF00FF || 800000 || 66CDAA || 0000CD || BA55D3 || 9370D8 || 3CB371 || 7B68EE || 00FA9A || 48D1CC || C71585 || 191970 || F5FFFA || FFE4E1 || FFE4B5 || FFDEAD || 000080 || FDF5E6 || 808000 || 688E23 || FFA500 || FF4500 || DA70D6 || EEE8AA || 98FB98 || AFEEEE || D87093 || FFEFD5 || FFDAB9 || CD853F || FFC0CB || DDA0DD || B0E0E6 || 800080 || FF0000 || BC8F8F || 4169E1 || 8B4513 || FA8072 || F4A460 || 2E8B57 || FFF5EE || A0522D || C0C0C0 || 87CEEB || 6A5ACD || 708090 || FFFAFA || 00FF7F || 4682B4 || D2B48C || 008080 || D8BFD8 || FF6347 || 40E0D0 || EE82EE || F5DEB3 || FFFFFF || F5F5F5 || FFFF00 || 9ACD32Color code in respective color | order BY COLOR
FFC0CB || FFB6C1 || FF69B4 || FF1493 || D87093 || C71585 || E6E6FA || D8BFD8 || DDA0DD || DA70D6 || EE82EE || FF00FF || FF00FF || BA55D3 || 9932CC || 9400D3 || 8A2BE2 || 8B008B || 800080 || 9370D8 || 7B68EE || 6A5ACD || 483D8B || 663399 || 4B0082 || FFA07A || FA8072 || E9967A || F08080 || CD5C5C || DC143C || FF0000 || B22222 || 8B0000 || 800000 || FFA500 || FF8C00 || FF7F50 || FF6347 || FF4500 || FFD700 || FFFF00 || FFFFE0 || FFFACD || FAFAD2 || FFEFD5 || FFE4B5 || FFDAB9 || EEE8AA || F0E68C || BDB76B || DAA520 || B8860B || ADFF2F || 7FFF00 || 7CFC00 || 00FF00 || 32CD32 || 98FB98 || 90EE90 || 00FA9A || 00FF7F || 3CB371 || 2E8B57 || 228B22 || 008000 || 006400 || 9ACD32 || 688E23 || 808000 || 556B2F || 66CDAA || 8FBC8F || 20B2AA || 008B8B || 008080 || 00FFFF || 00FFFF || E0FFFF || AFEEEE || 7FFFD4 || 40E0D0 || 48D1CC || 00CED1 || 5F9EA0 || 4682B4 || B0C4DE || ADD8E6 || B0E0E6 || 87CEFA87CEEB || 6495ED || 00BFFF || 1E90FF || 4169E1 || 0000FF || 0000CD || 00008B || 000080 || 191970CODE OF THE SPOILERS ABOVE
[spoiler=Color name | Test Text |ALBHABETICAL order]Antiquewhite | [color=FAEBD7][size=18][b]Test text[/b][/size][/color] || Aqua | [color=00FFFF][size=18][b]Test text[/b][/size][/color] || Aquamarine | [color=7FFFD4][size=18][b]Test text[/b][/size][/color] || Azure | [color=F0FFFF][size=18][b]Test text[/b][/size][/color] || Beige | [color=F5F5DC][size=18][b]Test text[/b][/size][/color] || Bisque | [color=FFE4C4][size=18][b]Test text[/b][/size][/color] || Blanchedalmond | [color=FFEBCD][size=18][b]Test text[/b][/size][/color] || Blue | [color=0000FF][size=18][b]Test text[/b][/size][/color] || Blueviolet | [color=8A2BE2][size=18][b]Test text[/b][/size][/color] || Brown | [color=A52A2A][size=18][b]Test text[/b][/size][/color] || Burlywood | [color=DEB887][size=18][b]Test text[/b][/size][/color] || Cadetblue | [color=5F9EA0][size=18][b]Test text[/b][/size][/color] || Chartreuse | [color=7FFF00][size=18][b]Test text[/b][/size][/color] || Chocolate | [color=D2691E][size=18][b]Test text[/b][/size][/color] || Coral | [color=FF7F50][size=18][b]Test text[/b][/size][/color] || Cornflowerblue | [color=6495ED][size=18][b]Test text[/b][/size][/color] || Cornsilk | [color=FFF8DC][size=18][b]Test text[/b][/size][/color] || Crimson | [color=DC143C][size=18][b]Test text[/b][/size][/color] || Cyan | [color=00FFFF][size=18][b]Test text[/b][/size][/color] || Darkblue | [color=00008B][size=18][b]Test text[/b][/size][/color] || Darkcyan | [color=008B8B][size=18][b]Test text[/b][/size][/color] || Darkgoldenrod | [color=B8860B][size=18][b]Test text[/b][/size][/color] || Darkgray | [color=A9A9A9][size=18][b]Test text[/b][/size][/color] || Darkgreen | [color=006400][size=18][b]Test text[/b][/size][/color] || Darkkhaki | [color=BDB76B][size=18][b]Test text[/b][/size][/color] || Darkmagenta | [color=8B008B][size=18][b]Test text[/b][/size][/color] || Darkolivegreen | [color=556B2F][size=18][b]Test text[/b][/size][/color] || Darkorange | [color=FF8C00][size=18][b]Test text[/b][/size][/color] || Darkorchid | [color=9932CC][size=18][b]Test text[/b][/size][/color] || Darkred | [color=8B0000][size=18][b]Test text[/b][/size][/color] || Darksalmon | [color=E9967A][size=18][b]Test text[/b][/size][/color] || Darkseagreen | [color=8FBC8F][size=18][b]Test text[/b][/size][/color] || Darkslateblue | [color=483D8B][size=18][b]Test text[/b][/size][/color] || Darkslategray | [color=2F4F4F][size=18][b]Test text[/b][/size][/color] || Darkturquoise | [color=00CED1][size=18][b]Test text[/b][/size][/color] || Darkviolet | [color=9400D3][size=18][b]Test text[/b][/size][/color] || Deeppink | [color=FF1493][size=18][b]Test text[/b][/size][/color] || Deepskyblue | [color=00BFFF][size=18][b]Test text[/b][/size][/color] || Dimgray | [color=696969][size=18][b]Test text[/b][/size][/color] || Dodgerblue | [color=1E90FF][size=18][b]Test text[/b][/size][/color] || Firebrick | [color=B22222][size=18][b]Test text[/b][/size][/color] || Floralwhite | [color=FFFAF0][size=18][b]Test text[/b][/size][/color] || Forestgreen | [color=228B22][size=18][b]Test text[/b][/size][/color] || Fuchsia | [color=FF00FF][size=18][b]Test text[/b][/size][/color] || Gainsboro | [color=DCDCDC][size=18][b]Test text[/b][/size][/color] || Ghostwhite | [color=F8F8FF][size=18][b]Test text[/b][/size][/color] || Gold | [color=FFD700][size=18][b]Test text[/b][/size][/color] || Goldenrod | [color=DAA520][size=18][b]Test text[/b][/size][/color] || Gray | [color=808080][size=18][b]Test text[/b][/size][/color] || Green | [color=008000][size=18][b]Test text[/b][/size][/color] || Greenyellow | [color=ADFF2F][size=18][b]Test text[/b][/size][/color] || Honeydew | [color=F0FFF0][size=18][b]Test text[/b][/size][/color] || Hotpink | [color=FF69B4][size=18][b]Test text[/b][/size][/color] || Indianred | [color=CD5C5C][size=18][b]Test text[/b][/size][/color] || Indigo | [color=4B0082][size=18][b]Test text[/b][/size][/color] || Ivory | [color=FFFFF0][size=18][b]Test text[/b][/size][/color] || Khaki | [color=F0E68C][size=18][b]Test text[/b][/size][/color] || Lavender | [color=E6E6FA][size=18][b]Test text[/b][/size][/color] || Lavenderblush | [color=FFF0F5][size=18][b]Test text[/b][/size][/color] || Lawngreen | [color=7CFC00][size=18][b]Test text[/b][/size][/color] || Lemonchiffon | [color=FFFACD][size=18][b]Test text[/b][/size][/color] || Lightblue | [color=ADD8E6][size=18][b]Test text[/b][/size][/color] || Lightcoral | [color=F08080][size=18][b]Test text[/b][/size][/color] || Lightcyan | [color=E0FFFF][size=18][b]Test text[/b][/size][/color] || Lightgoldenrodyellow | [color=FAFAD2][size=18][b]Test text[/b][/size][/color] || Lightgreen | [color=90EE90][size=18][b]Test text[/b][/size][/color] || Lightgrey | [color=D3D3D3][size=18][b]Test text[/b][/size][/color] || Lightpink | [color=FFB6C1][size=18][b]Test text[/b][/size][/color] || Lightsalmon | [color=FFA07A][size=18][b]Test text[/b][/size][/color] || Lightseagreen | [color=20B2AA][size=18][b]Test text[/b][/size][/color] || Lightskyblue | [color=87CEFA][size=18][b]Test text[/b][/size][/color] || Lightslategray | [color=778899][size=18][b]Test text[/b][/size][/color] || Lightsteelblue | [color=B0C4DE]][size=18][b]Test text[/b][/size][/color] || Linen | [color=FAF0E6][size=18][b]Test text[/b][/size][/color] || Magenta | [color=FF00FF][size=18][b]Test text[/b][/size][/color] || Maroon | [color=800000][size=18][b]Test text[/b][/size][/color] || Mediumaquamarine | [color=66CDAA][size=18][b]Test text[/b][/size][/color] || Mediumblue | [color=0000CD][size=18][b]Test text[/b][/size][/color] || Mediumorchid | [color=BA55D3][size=18][b]Test text[/b][/size][/color] || Mediumpurple | [color=9370D8][size=18][b]Test text[/b][/size][/color] || Mediumseagreen | [color=3CB371][size=18][b]Test text[/b][/size][/color] || Mediumslateblue | [color=7B68EE][size=18][b]Test text[/b][/size][/color] || Mediumspringgreen | [color=00FA9A][size=18][b]Test text[/b][/size][/color] || Mediumturquoise | [color=48D1CC][size=18][b]Test text[/b][/size][/color] || Mediumvioletred | [color=C71585][size=18][b]Test text[/b][/size][/color] || Midnightblue | [color=191970][size=18][b]Test text[/b][/size][/color] || Mintcream | [color=F5FFFA][size=18][b]Test text[/b][/size][/color] || Mistyrose | [color=FFE4E1][size=18][b]Test text[/b][/size][/color] || Moccasin | [color=FFE4B5][size=18][b]Test text[/b][/size][/color] || Navajowhite | [color=FFDEAD][size=18][b]Test text[/b][/size][/color] || Navy | [color=000080][size=18][b]Test text[/b][/size][/color] || Oldlace | [color=FDF5E6][size=18][b]Test text[/b][/size][/color] || Olive | [color=808000][size=18][b]Test text[/b][/size][/color] || Olivedrab | [color=688E23][size=18][b]Test text[/b][/size][/color] || Orange | [color=FFA500][size=18][b]Test text[/b][/size][/color] || Orangered | [color=FF4500][size=18][b]Test text[/b][/size][/color] || Orchid | [color=DA70D6][size=18][b]Test text[/b][/size][/color] || Palegoldenrod | [color=EEE8AA][size=18][b]Test text[/b][/size][/color] || Palegreen | [color=98FB98][size=18][b]Test text[/b][/size][/color] || Paleturquoise | [color=AFEEEE][size=18][b]Test text[/b][/size][/color] || Palevioletred | [color=D87093][size=18][b]Test text[/b][/size][/color] || Papayawhip | [color=FFEFD5][size=18][b]Test text[/b][/size][/color] || Peachpuff | [color=FFDAB9][size=18][b]Test text[/b][/size][/color] || Peru | [color=CD853F][size=18][b]Test text[/b][/size][/color] || Pink | [color=FFC0CB][size=18][b]Test text[/b][/size][/color] || Plum | [color=DDA0DD][size=18][b]Test text[/b][/size][/color] || Powderblue | [color=B0E0E6][size=18][b]Test text[/b][/size][/color] || Purple | [color=800080][size=18][b]Test text[/b][/size][/color] || Red | [color=FF0000][size=18][b]Test text[/b][/size][/color] || Rosybrown | [color=BC8F8F][size=18][b]Test text[/b][/size][/color] || Royalblue | [color=4169E1][size=18][b]Test text[/b][/size][/color] || Saddlebrown | [color=8B4513][size=18][b]Test text[/b][/size][/color] || Salmon | [color=FA8072][size=18][b]Test text[/b][/size][/color] || Sandybrown | [color=F4A460][size=18][b]Test text[/b][/size][/color] || Seagreen | [color=2E8B57][size=18][b]Test text[/b][/size][/color] || Seashell | [color=FFF5EE][size=18][b]Test text[/b][/size][/color] || Sienna | [color=A0522D][size=18][b]Test text[/b][/size][/color] || Silver | [color=C0C0C0][size=18][b]Test text[/b][/size][/color] || Skyblue | [color=87CEEB][size=18][b]Test text[/b][/size][/color] || Slateblue | [color=6A5ACD][size=18][b]Test text[/b][/size][/color] || Slategray | [color=708090][size=18][b]Test text[/b][/size][/color] || Snow | [color=FFFAFA][size=18][b]Test text[/b][/size][/color] || Springgreen | [color=00FF7F][size=18][b]Test text[/b][/size][/color] || Steelblue | [color=4682B4][size=18][b]Test text[/b][/size][/color] || Tan | [color=D2B48C][size=18][b]Test text[/b][/size][/color] || Teal | [color=008080][size=18][b]Test text[/b][/size][/color] || Thistle | [color=D8BFD8][size=18][b]Test text[/b][/size][/color] || Tomato | [color=FF6347][size=18][b]Test text[/b][/size][/color] || Turquoise | [color=40E0D0][size=18][b]Test text[/b][/size][/color] || Violet | [color=EE82EE][size=18][b]Test text[/b][/size][/color] || Wheat | [color=F5DEB3][size=18][b]Test text[/b][/size][/color] || White | [color=FFFFFF][size=18][b]Test text[/b][/size][/color] || Whitesmoke | [color=F5F5F5][size=18][b]Test text[/b][/size][/color] || Yellow | [color=FFFF00][size=18][b]Test text[/b][/size][/color] || Yellowgreen | [color=9ACD32][size=18][b]Test text[/b][/size][/color][/spoiler]
[spoiler=Color name | Test Text | order BY COLOR]Pink | [color=FFC0CB][size=18][b]Test text[/b][/size][/color] || Lightpink | [color=FFB6C1][size=18][b]Test text[/b][/size][/color] || Hotpink | [color=FF69B4][size=18][b]Test text[/b][/size][/color] || Deeppink | [color=FF1493][size=18][b]Test text[/b][/size][/color] || Palevioletred | [color=D87093][size=18][b]Test text[/b][/size][/color] || Mediumvioletred | [color=C71585][size=18][b]Test text[/b][/size][/color] || Lavender | [color=E6E6FA][size=18][b]Test text[/b][/size][/color] || Thistle | [color=D8BFD8][size=18][b]Test text[/b][/size][/color] || Plum | [color=DDA0DD][size=18][b]Test text[/b][/size][/color] || Orchid | [color=DA70D6][size=18][b]Test text[/b][/size][/color] || Violet | [color=EE82EE][size=18][b]Test text[/b][/size][/color] || Fuchsia | [color=FF00FF][size=18][b]Test text[/b][/size][/color] || Magenta | [color=FF00FF][size=18][b]Test text[/b][/size][/color] || Mediumorchid | [color=BA55D3][size=18][b]Test text[/b][/size][/color] || Darkorchid | [color=9932CC][size=18][b]Test text[/b][/size][/color] || Darkviolet | [color=9400D3][size=18][b]Test text[/b][/size][/color] || Blueviolet | [color=8A2BE2][size=18][b]Test text[/b][/size][/color] || Darkmagenta | [color=8B008B][size=18][b]Test text[/b][/size][/color] || Purple | [color=800080][size=18][b]Test text[/b][/size][/color] || Mediumpurple | [color=9370D8][size=18][b]Test text[/b][/size][/color] || Mediumslateblue | [color=7B68EE][size=18][b]Test text[/b][/size][/color] || Slateblue | [color=6A5ACD][size=18][b]Test text[/b][/size][/color] || Darkslateblue | [color=483D8B][size=18][b]Test text[/b][/size][/color] || Rebeccapurple | [color=663399][size=18][b]Test text[/b][/size][/color] || Indigo | [color=4B0082][size=18][b]Test text[/b][/size][/color] || Lightsalmon | [color=FFA07A][size=18][b]Test text[/b][/size][/color] || Salmon | [color=FA8072][size=18][b]Test text[/b][/size][/color] || Darksalmon | [color=E9967A][size=18][b]Test text[/b][/size][/color] || Lightcoral | [color=F08080][size=18][b]Test text[/b][/size][/color] || Indianred | [color=CD5C5C][size=18][b]Test text[/b][/size][/color] || Crimson | [color=DC143C][size=18][b]Test text[/b][/size][/color] || Red | [color=FF0000][size=18][b]Test text[/b][/size][/color] || Firebrick | [color=B22222][size=18][b]Test text[/b][/size][/color] || Darkred | [color=8B0000][size=18][b]Test text[/b][/size][/color] || Maroon | [color=800000][size=18][b]Test text[/b][/size][/color] || Orange | [color=FFA500][size=18][b]Test text[/b][/size][/color] || Darkorange | [color=FF8C00][size=18][b]Test text[/b][/size][/color] || Coral | [color=FF7F50][size=18][b]Test text[/b][/size][/color] || Tomato | [color=FF6347][size=18][b]Test text[/b][/size][/color] || Orangered | [color=FF4500][size=18][b]Test text[/b][/size][/color] || Gold | [color=FFD700][size=18][b]Test text[/b][/size][/color] || Yellow | [color=FFFF00][size=18][b]Test text[/b][/size][/color] || Lightyellow | [color=FFFFE0][size=18][b]Test text[/b][/size][/color] || Lemonchiffon | [color=FFFACD][size=18][b]Test text[/b][/size][/color] || Lightgoldenrodyellow | [color=FAFAD2][size=18][b]Test text[/b][/size][/color] || Papayawhip | [color=FFEFD5][size=18][b]Test text[/b][/size][/color] || Moccasin | [color=FFE4B5][size=18][b]Test text[/b][/size][/color] || Peachpuff | [color=FFDAB9][size=18][b]Test text[/b][/size][/color] || Palegoldenrod | [color=EEE8AA][size=18][b]Test text[/b][/size][/color] || Khaki | [color=F0E68C][size=18][b]Test text[/b][/size][/color] || Darkkhaki | [color=BDB76B][size=18][b]Test text[/b][/size][/color] || Goldenrod | [color=DAA520][size=18][b]Test text[/b][/size][/color] || Darkgoldenrod | [color=B8860B][size=18][b]Test text[/b][/size][/color] || Greenyellow | [color=ADFF2F][size=18][b]Test text[/b][/size][/color] || Chartreuse | [color=7FFF00][size=18][b]Test text[/b][/size][/color] || Lawngreen | [color=7CFC00][size=18][b]Test text[/b][/size][/color] || Lime | [color=00FF00][size=18][b]Test text[/b][/size][/color] || Limegreen | [color=32CD32][size=18][b]Test text[/b][/size][/color] || Palegreen | [color=98FB98][size=18][b]Test text[/b][/size][/color] || Lightgreen | [color=90EE90][size=18][b]Test text[/b][/size][/color] || Mediumspringgreen | [color=00FA9A][size=18][b]Test text[/b][/size][/color] || Springgreen | [color=00FF7F][size=18][b]Test text[/b][/size][/color] || Mediumseagreen | [color=3CB371][size=18][b]Test text[/b][/size][/color] || Seagreen | [color=2E8B57][size=18][b]Test text[/b][/size][/color] || Forestgreen | [color=228B22][size=18][b]Test text[/b][/size][/color] || Green | [color=008000][size=18][b]Test text[/b][/size][/color] || Darkgreen | [color=006400][size=18][b]Test text[/b][/size][/color] || Yellowgreen | [color=9ACD32][size=18][b]Test text[/b][/size][/color] || Olivedrab | [color=688E23][size=18][b]Test text[/b][/size][/color] || Olive | [color=808000][size=18][b]Test text[/b][/size][/color] || Darkolivegreen | [color=556B2F][size=18][b]Test text[/b][/size][/color] || Mediumaquamarine | [color=66CDAA][size=18][b]Test text[/b][/size][/color] || Darkseagreen | [color=8FBC8F][size=18][b]Test text[/b][/size][/color] || Lightseagreen | [color=20B2AA][size=18][b]Test text[/b][/size][/color] || Darkcyan | [color=008B8B][size=18][b]Test text[/b][/size][/color] || Teal | [color=008080][size=18][b]Test text[/b][/size][/color] || Aqua | [color=00FFFF][size=18][b]Test text[/b][/size][/color] || Cyan | [color=00FFFF][size=18][b]Test text[/b][/size][/color] || Lightcyan | [color=E0FFFF][size=18][b]Test text[/b][/size][/color] || Paleturquoise | [color=AFEEEE][size=18][b]Test text[/b][/size][/color] || Aquamarine | [color=7FFFD4][size=18][b]Test text[/b][/size][/color] || Turquoise | [color=40E0D0][size=18][b]Test text[/b][/size][/color] || Mediumturquoise | [color=48D1CC][size=18][b]Test text[/b][/size][/color] || Darkturquoise | [color=00CED1][size=18][b]Test text[/b][/size][/color] || Cadetblue | [color=5F9EA0][size=18][b]Test text[/b][/size][/color] || Steelblue | [color=4682B4][size=18][b]Test text[/b][/size][/color] || Lightsteelblue | [color=B0C4DE][size=18][b]Test text[/b][/size][/color] || Lightblue | [color=ADD8E6][size=18][b]Test text[/b][/size][/color] || Powderblue | [color=B0E0E6][size=18][b]Test text[/b][/size][/color] || Lightskyblue | [color=87CEFA][size=18][b]Test text[/b][/size][/color] || Skyblue | [color=87CEEB][size=18][b]Test text[/b][/size][/color] || Cornflowerblue | [color=6495ED][size=18][b]Test text[/b][/size][/color] || Deepskyblue | [color=00BFFF][size=18][b]Test text[/b][/size][/color] || Dodgerblue | [color=1E90FF][size=18][b]Test text[/b][/size][/color] || Royalblue | [color=4169E1][size=18][b]Test text[/b][/size][/color] || Blue | [color=0000FF][size=18][b]Test text[/b][/size][/color] || Mediumblue | [color=0000CD][size=18][b]Test text[/b][/size][/color] || Darkblue | [color=00008B][size=18][b]Test text[/b][/size][/color] || Navy | [color=000080][size=18][b]Test text[/b][/size][/color] || Midnightblue | [color=191970][size=18][b]Test text[/b][/size][/color][/spoiler]
[spoiler=Color code in respective color | ALBABETICAL order ][color=Antiquewhite][b][size=16]FAEBD7[/b][/size][/color] || [color=[color=Aqua][b][size=16]00FFFF[/b][/size][/color] || [color=Aquamarine][b][size=16]7FFFD4[/b][/size][/color] || [color=Azure][b][size=16]F0FFFF[/b][/size][/color] || [color=Beige][b][size=16]F5F5DC[/b][/size][/color] || [color=Bisque][b][size=16]FFE4C4[/b][/size][/color] || [color=Blanchedalmond][b][size=16]FFEBCD[/b][/size][/color] || [color=Blue][b][size=16]0000FF[/b][/size][/color] || [color=Blueviolet][b][size=16]8A2BE2[/b][/size][/color] || [color=Brown][b][size=16]A52A2A[/b][/size][/color] || [color=Burlywood][b][size=16]DEB887[/b][/size][/color] || [color=Cadetblue][b][size=16]5F9EA0[/b][/size][/color] || [color=Chartreuse][b][size=16]7FFF00[/b][/size][/color] || [color=Chocolate][b][size=16]D2691E[/b][/size][/color] || [color=Coral][b][size=16]FF7F50[/b][/size][/color] || [color=Cornflowerblue][b][size=16]6495ED[/b][/size][/color] || [color=Cornsilk][b][size=16]FFF8DC[/b][/size][/color] || [color=Crimson][b][size=16]DC143C[/b][/size][/color] || [color=Cyan][b][size=16]00FFFF[/b][/size][/color] || [color=Darkblue][b][size=16]00008B[/b][/size][/color] || [color=Darkcyan][b][size=16]008B8B[/b][/size][/color] || [color=Darkgoldenrod][b][size=16]B8860B[/b][/size][/color] || [color=Darkgray][b][size=16]A9A9A9[/b][/size][/color] || [color=Darkgreen][b][size=16]006400[/b][/size][/color] || [color=Darkkhaki][b][size=16]BDB76B[/b][/size][/color] || [color=Darkmagenta][b][size=16]8B008B[/b][/size][/color] || [color=Darkolivegreen][b][size=16]556B2F[/b][/size][/color] || [color=Darkorange][b][size=16]FF8C00[/b][/size][/color] || [color=Darkorchid][b][size=16]9932CC[/b][/size][/color] || [color=Darkred][b][size=16]8B0000[/b][/size][/color] || [color=Darksalmon][b][size=16]E9967A[/b][/size][/color] || [color=Darkseagreen][b][size=16]8FBC8F[/b][/size][/color] || [color=Darkslateblue][b][size=16]483D8B[/b][/size][/color] || [color=Darkslategray][b][size=16]2F4F4F[/b][/size][/color] || [color=Darkturquoise][b][size=16]00CED1[/b][/size][/color] || [color=Darkviolet][b][size=16]9400D3[/b][/size][/color] || [color=Deeppink][b][size=16]FF1493[/b][/size][/color] || [color=Deepskyblue][b][size=16]00BFFF[/b][/size][/color] || [color=Dimgray][b][size=16]696969[/b][/size][/color] || [color=Dodgerblue][b][size=16]1E90FF[/b][/size][/color] || [color=Firebrick][b][size=16]B22222[/b][/size][/color] || [color=Floralwhite][b][size=16]FFFAF0[/b][/size][/color] || [color=Forestgreen][b][size=16]228B22[/b][/size][/color] || [color=Fuchsia][b][size=16]FF00FF[/b][/size][/color] || [color=Gainsboro][b][size=16]DCDCDC[/b][/size][/color] || [color=Ghostwhite][b][size=16]F8F8FF[/b][/size][/color] || [color=Gold][b][size=16]FFD700[/b][/size][/color] || [color=Goldenrod][b][size=16]DAA520[/b][/size][/color] || [color=Gray][b][size=16]808080[/b][/size][/color] || [color=Green][b][size=16]008000[/b][/size][/color] || [color=Greenyellow][b][size=16]ADFF2F[/b][/size][/color] || [color=Honeydew][b][size=16]F0FFF0[/b][/size][/color] || [color=Hotpink][b][size=16]FF69B4[/b][/size][/color] || [color=Indianred][b][size=16]CD5C5C[/b][/size][/color] || [color=Indigo][b][size=16]4B0082[/b][/size][/color] || [color=Ivory][b][size=16]FFFFF0[/b][/size][/color] || [color=Khaki][b][size=16]F0E68C[/b][/size][/color] || [color=Lavender][b][size=16]E6E6FA[/b][/size][/color] || [color=Lavenderblush][b][size=16]FFF0F5[/b][/size][/color] || [color=Lawngreen][b][size=16]7CFC00[/b][/size][/color] || [color=Lemonchiffon][b][size=16]FFFACD[/b][/size][/color] || [color=Lightblue][b][size=16]ADD8E6[/b][/size][/color] || [color=Lightcoral][b][size=16]F08080[/b][/size][/color] || [color=Lightcyan][b][size=16]E0FFFF[/b][/size][/color] || [color=Lightgoldenrodyellow][b][size=16]FAFAD2[/b][/size][/color] || [color=Lightgreen][b][size=16]90EE90[/b][/size][/color] || [color=Lightgrey][b][size=16]D3D3D3[/b][/size][/color] || [color=Lightpink][b][size=16]FFB6C1[/b][/size][/color] || [color=Lightsalmon][b][size=16]FFA07A[/b][/size][/color] || [color=Lightseagreen][b][size=16]20B2AA[/b][/size][/color] || [color=Lightskyblue][b][size=16]87CEFA[/b][/size][/color] || [color=Lightslategray][b][size=16]778899[/b][/size][/color] || [color=Lightsteelblue][b][size=16]B0C4DE][/b][/size][/color] || [color=Linen][b][size=16]FAF0E6[/b][/size][/color] || [color=Magenta][b][size=16]FF00FF[/b][/size][/color] || [color=Maroon][b][size=16]800000[/b][/size][/color] || [color=Mediumaquamarine][b][size=16]66CDAA[/b][/size][/color] || [color=Mediumblue][b][size=16]0000CD[/b][/size][/color] || [color=Mediumorchid][b][size=16]BA55D3[/b][/size][/color] || [color=Mediumpurple][b][size=16]9370D8[/b][/size][/color] || [color=Mediumseagreen][b][size=16]3CB371[/b][/size][/color] || [color=Mediumslateblue][b][size=16]7B68EE[/b][/size][/color] || [color=Mediumspringgreen][b][size=16]00FA9A[/b][/size][/color] || [color=Mediumturquoise][b][size=16]48D1CC[/b][/size][/color] || [color=Mediumvioletred][b][size=16]C71585[/b][/size][/color] || [color=Midnightblue][b][size=16]191970[/b][/size][/color] || [color=Mintcream][b][size=16]F5FFFA[/b][/size][/color] || [color=Mistyrose][b][size=16]FFE4E1[/b][/size][/color] || [color=Moccasin][b][size=16]FFE4B5[/b][/size][/color] || [color=Navajowhite][b][size=16]FFDEAD[/b][/size][/color] || [color=Navy][b][size=16]000080[/b][/size][/color] || [color=Oldlace][b][size=16]FDF5E6[/b][/size][/color] || [color=Olive][b][size=16]808000[/b][/size][/color] || [color=Olivedrab][b][size=16]688E23[/b][/size][/color] || [color=Orange][b][size=16]FFA500[/b][/size][/color] || [color=Orangered][b][size=16]FF4500[/b][/size][/color] || [color=Orchid][b][size=16]DA70D6[/b][/size][/color] || [color=Palegoldenrod][b][size=16]EEE8AA[/b][/size][/color] || [color=Palegreen][b][size=16]98FB98[/b][/size][/color] || [color=Paleturquoise][b][size=16]AFEEEE[/b][/size][/color] || [color=Palevioletred][b][size=16]D87093[/b][/size][/color] || [color=Papayawhip][b][size=16]FFEFD5[/b][/size][/color] || [color=Peachpuff][b][size=16]FFDAB9[/b][/size][/color] || [color=Peru][b][size=16]CD853F[/b][/size][/color] || [color=Pink][b][size=16]FFC0CB[/b][/size][/color] || [color=Plum][b][size=16]DDA0DD[/b][/size][/color] || [color=Powderblue][b][size=16]B0E0E6[/b][/size][/color] || [color=Purple][b][size=16]800080[/b][/size][/color] || [color=Red][b][size=16]FF0000[/b][/size][/color] || [color=Rosybrown][b][size=16]BC8F8F[/b][/size][/color] || [color=Royalblue][b][size=16]4169E1[/b][/size][/color] || [color=Saddlebrown][b][size=16]8B4513[/b][/size][/color] || [color=Salmon][b][size=16]FA8072[/b][/size][/color] || [color=Sandybrown][b][size=16]F4A460[/b][/size][/color] || [color=Seagreen][b][size=16]2E8B57[/b][/size][/color] || [color=Seashell][b][size=16]FFF5EE[/b][/size][/color] || [color=Sienna][b][size=16]A0522D[/b][/size][/color] || [color=Silver][b][size=16]C0C0C0[/b][/size][/color] || [color=Skyblue][b][size=16]87CEEB[/b][/size][/color] || [color=Slateblue][b][size=16]6A5ACD[/b][/size][/color] || [color=Slategray][b][size=16]708090[/b][/size][/color] || [color=Snow][b][size=16]FFFAFA[/b][/size][/color] || [color=Springgreen][b][size=16]00FF7F[/b][/size][/color] || [color=Steelblue][b][size=16]4682B4[/b][/size][/color] || [color=Tan][b][size=16]D2B48C[/b][/size][/color] || [color=Teal][b][size=16]008080[/b][/size][/color] || [color=Thistle][b][size=16]D8BFD8[/b][/size][/color] || [color=Tomato][b][size=16]FF6347[/b][/size][/color] || [color=Turquoise][b][size=16]40E0D0[/b][/size][/color] || [color=Violet][b][size=16]EE82EE[/b][/size][/color] || [color=Wheat][b][size=16]F5DEB3[/b][/size][/color] || [color=White][b][size=16]FFFFFF[/b][/size][/color] || [color=Whitesmoke][b][size=16]F5F5F5[/b][/size][/color] || [color=Yellow][b][size=16]FFFF00[/b][/size][/color] || [color=Yellowgreen][b][size=16]9ACD32[/b][/size][/color][/spoiler]
[hr]
[hr]
[spoiler=Color code in respective color | order BY COLOR][color=Pink][b][size=16]FFC0CB[/b][/size][/color] || [color=Lightpink][b][size=16]FFB6C1[/b][/size][/color] || [color=Hotpink][b][size=16]FF69B4[/b][/size][/color] || [color=Deeppink][b][size=16]FF1493[/b][/size][/color] || [color=Palevioletred][b][size=16]D87093[/b][/size][/color] || [color=Mediumvioletred][b][size=16]C71585[/b][/size][/color] || [color=Lavender][b][size=16]E6E6FA[/b][/size][/color] || [color=Thistle][b][size=16]D8BFD8[/b][/size][/color] || [color=Plum][b][size=16]DDA0DD[/b][/size][/color] || [color=Orchid][b][size=16]DA70D6[/b][/size][/color] || [color=Violet][b][size=16]EE82EE[/b][/size][/color] || [color=Fuchsia][b][size=16]FF00FF[/b][/size][/color] || [color=Magenta][b][size=16]FF00FF[/b][/size][/color] || [color=Mediumorchid][b][size=16]BA55D3[/b][/size][/color] || [color=Darkorchid][b][size=16]9932CC[/b][/size][/color] || [color=Darkviolet][b][size=16]9400D3[/b][/size][/color] || [color=Blueviolet][b][size=16]8A2BE2[/b][/size][/color] || [color=Darkmagenta][b][size=16]8B008B[/b][/size][/color] || [color=Purple][b][size=16]800080[/b][/size][/color] || [color=Mediumpurple][b][size=16]9370D8[/b][/size][/color] || [color=Mediumslateblue][b][size=16]7B68EE[/b][/size][/color] || [color=Slateblue][b][size=16]6A5ACD[/b][/size][/color] || [color=Darkslateblue][b][size=16]483D8B[/b][/size][/color] || [color=Rebeccapurple][b][size=16]663399[/b][/size][/color] || [color=Indigo][b][size=16]4B0082[/b][/size][/color] || [color=Lightsalmon][b][size=16]FFA07A[/b][/size][/color] || [color=Salmon][b][size=16]FA8072[/b][/size][/color] || [color=Darksalmon][b][size=16]E9967A[/b][/size][/color] || [color=Lightcoral][b][size=16]F08080[/b][/size][/color] || [color=Indianred][b][size=16]CD5C5C[/b][/size][/color] || [color=Crimson][b][size=16]DC143C[/b][/size][/color] || [color=Red][b][size=16]FF0000[/b][/size][/color] || [color=Firebrick][b][size=16]B22222[/b][/size][/color] || [color=Darkred][b][size=16]8B0000[/b][/size][/color] || [color=Maroon][b][size=16]800000[/b][/size][/color] || [color=Orange][b][size=16]FFA500[/b][/size][/color] || [color=Darkorange][b][size=16]FF8C00[/b][/size][/color] || [color=Coral][b][size=16]FF7F50[/b][/size][/color] || [color=Tomato][b][size=16]FF6347[/b][/size][/color] || [color=Orangered][b][size=16]FF4500[/b][/size][/color] || [color=Gold][b][size=16]FFD700[/b][/size][/color] || [color=Yellow][b][size=16]FFFF00[/b][/size][/color] || [color=Lightyellow][b][size=16]FFFFE0[/b][/size][/color] || [color=Lemonchiffon][b][size=16]FFFACD[/b][/size][/color] || [color=Lightgoldenrodyellow][b][size=16]FAFAD2[/b][/size][/color] || [color=Papayawhip][b][size=16]FFEFD5[/b][/size][/color] || [color=Moccasin][b][size=16]FFE4B5[/b][/size][/color] || [color=Peachpuff][b][size=16]FFDAB9[/b][/size][/color] || [color=Palegoldenrod][b][size=16]EEE8AA[/b][/size][/color] || [color=Khaki][b][size=16]F0E68C[/b][/size][/color] || [color=Darkkhaki][b][size=16]BDB76B[/b][/size][/color] || [color=Goldenrod][b][size=16]DAA520[/b][/size][/color] || [color=Darkgoldenrod][b][size=16]B8860B[/b][/size][/color] || [color=Greenyellow][b][size=16]ADFF2F[/b][/size][/color] || [color=Chartreuse][b][size=16]7FFF00[/b][/size][/color] || [color=Lawngreen][b][size=16]7CFC00[/b][/size][/color] || [color=Lime][b][size=16]00FF00[/b][/size][/color] || [color=Limegreen][b][size=16]32CD32[/b][/size][/color] || [color=Palegreen][b][size=16]98FB98[/b][/size][/color] || [color=Lightgreen][b][size=16]90EE90[/b][/size][/color] || [color=Mediumspringgreen][b][size=16]00FA9A[/b][/size][/color] || [color=Springgreen][b][size=16]00FF7F[/b][/size][/color] || [color=Mediumseagreen][b][size=16]3CB371[/b][/size][/color] || [color=Seagreen][b][size=16]2E8B57[/b][/size][/color] || [color=Forestgreen][b][size=16]228B22[/b][/size][/color] || [color=Green][b][size=16]008000[/b][/size][/color] || [color=Darkgreen][b][size=16]006400[/b][/size][/color] || [color=Yellowgreen][b][size=16]9ACD32[/b][/size][/color] || [color=Olivedrab][b][size=16]688E23[/b][/size][/color] || [color=Olive][b][size=16]808000[/b][/size][/color] || [color=Darkolivegreen][b][size=16]556B2F[/b][/size][/color] || [color=Mediumaquamarine][b][size=16]66CDAA[/b][/size][/color] || [color=Darkseagreen][b][size=16]8FBC8F[/b][/size][/color] || [color=Lightseagreen][b][size=16]20B2AA[/b][/size][/color] || [color=Darkcyan][b][size=16]008B8B[/b][/size][/color] || [color=Teal][b][size=16]008080[/b][/size][/color] || [color=Aqua][b][size=16]00FFFF[/b][/size][/color] || [color=Cyan][b][size=16]00FFFF[/b][/size][/color] || [color=Lightcyan][b][size=16]E0FFFF[/b][/size][/color] || [color=Paleturquoise][b][size=16]AFEEEE[/b][/size][/color] || [color=Aquamarine][b][size=16]7FFFD4[/b][/size][/color] || [color=Turquoise][b][size=16]40E0D0[/b][/size][/color] || [color=Mediumturquoise][b][size=16]48D1CC[/b][/size][/color] || [color=Darkturquoise][b][size=16]00CED1[/b][/size][/color] || [color=Cadetblue][b][size=16]5F9EA0[/b][/size][/color] || [color=Steelblue][b][size=16]4682B4[/b][/size][/color] || [color=Lightsteelblue][b][size=16]B0C4DE[/b][/size][/color] || [color=Lightblue][b][size=16]ADD8E6[/b][/size][/color] || [color=Powderblue][b][size=16]B0E0E6[/b][/size][/color] || [color=Lightskyblue][b][size=16]87CEFA[/b][/size][/color][color=Skyblue][b][size=16]87CEEB[/b][/size][/color] || [color=Cornflowerblue][b][size=16]6495ED[/b][/size][/color] || [color=Deepskyblue][b][size=16]00BFFF[/b][/size][/color] || [color=Dodgerblue][b][size=16]1E90FF[/b][/size][/color] || [color=Royalblue][b][size=16]4169E1[/b][/size][/color] || [color=Blue][b][size=16]0000FF[/b][/size][/color] || [color=Mediumblue][b][size=16]0000CD[/b][/size][/color] || [color=Darkblue][b][size=16]00008B[/b][/size][/color] || [color=Navy][b][size=16]000080[/b][/size][/color] || [color=Midnightblue][b][size=16]191970[/b][/size][/color][/spoiler]
Towards Federated Key Transparency
In late 2022, I blogged about the work needed to develop a specification for end-to-end encryption for the fediverse. I sketched out some of the key management components on GitHub, and then the public work abruptly stalled.
A few of you have wondered what’s the deal with that.
This post covers why this effort stalled, what I’m proposing we do next.
What’s The Hold Up?
The “easy” (relatively speaking) parts of the problem are as follows:
- Secret key management. (This is sketched out already, and provides multiple mechanisms for managing secret key material. Yay!)
- Bulk encryption of messages and media. (I’ve done a lot of work in this space over the years, so it’s an area I’m deeply familiar with. When we get to this part, it will be almost trivial. I’m not worried about it at all.)
- Forward-secure ratcheting / authenticated key exchange / group key agreement. (RFC 9420 is a great starting point.)
That is to say, managing secret keys, using secret keys, and deriving shared secret keys are all in the “easy” bucket.
The hard part? Public key management.
CMYKat made this
Why is Public Key Management Hard?
In a centralized service (think: Twitter, Facebook, etc.), this is actually much easier to build: Shove your public keys into a database, and design your client-side software to trust whatever public key your server gives them. Bob’s your uncle, pack it up and go home.
Unfortunately, it’s kind of stupid to build anything that way.
If you explicitly trust the server, the server could provide the wrong public key (i.e., one for which the server knows the corresponding secret key) and you’ll be none the wiser. This makes it trivial for the server to intercept and read your messages.
If your users are trusting you regardless, they’re probably just as happy if you don’t encrypt at the endpoint at all (beyond using TLS, but transport encryption is table stakes for any online service so nevermind that).
But let’s say you wanted to encrypt between peers anyway, because you’re feeling generous (or don’t want to field a bunch of questionably legal demands for user data by law enforcement; a.k.a. the Snapchat threat model).
You could improve endpoint trust by shoving all of your users’ public keys into an append-only data structure; i.e. key transparency, like WhatsApp proposed in 2023:
youtube.com/watch?v=_N4Q05z5vP…
And, to be perfectly clear, key transparency is a damn good idea.
Key transparency keeps everyone honest and makes it difficult for criminals to secretly replace a victim’s public key, because the act of doing so is unavoidably published to an append-only log.
The primary challenge is scaling a transparency feature to serve a public, federated system.
Federated Key Transparency?
Despite appearances, I haven’t been sitting on my thumbs for the past year or so. I’ve been talking with cryptography experts about their projects and papers in the same space.
Truthfully, I had been hoping to piggyback off one of those upcoming projects (which is focused more on public key discovery for SAML- and OAuth-like protocols) to build the Federated PKI piece for E2EE for the Fediverse.
Unfortunately, that project keeps getting delayed and pushed back, and I’ve just about run out of patience for it.
Additionally, there are some engineering challenges that I would need to tackle to build atop it, so it’s not as simple as “let’s just use that protocol”, either.
So let’s do something else instead:
Art: ScruffKerfluff
Fediverse Public Key Directories
Orthogonal to the overall Fediverse E2EE specification project, let’s build a Public Key Directory for the Fediverse.
This will not only be useful for building a coherent specification for E2EE (as it provides the “Federated PKI” component we’d need to build it securely), but it would also be extremely useful for software developers the whole world over.
Imagine this:
- If you want to fetch a user’s SSH public key, you can just query for their username and get a list of non-expired, non-revoked public keys to choose from.
- If you wanted public key pinning and key rotation for OAuth2 and/or OpenID Connect identity providers without having to update configurations or re-deploy any applications, you can do that.
- If you want to encrypt a message to a complete stranger, such that only they can decrypt it, without any sort of interaction (i.e., they could be offline for a holiday and still decrypt it when they get back), you could do that.
Oh, and best of all? You can get all these wins without propping up any cryptocurrency bullshit either.
From simple abstractions, great power may bloom.Mark Miller
How Will This Work?
We need to design a specific kind of server that speaks a limited set of the ActivityPub protocol.
I say “limited” because it will only not support editing or deleting messages provided by another instance. It will only append data.
To understand the full picture, let’s first look at the message types, public key types, and how the message types will be interpreted.
Message Types
Under the ActivityPub layer, we will need to specify a distinct set of Directory Message Types. An opening offer would look like this:
[strong]AddKey[/strong]
— contains an Asymmetric Public Key, a number mapped to the user, and instance that hosts it, and some other metadata (i.e., time)[strong]RevokeKey[/strong]
— marks an existing public key as revoked[strong]MoveIdentity[/strong]
— moves all of the public keys from identity A to identity B. This can be used for username changes or instance migrations.
We may choose to allow more message types at the front-end if need be, but that’s enough for our purposes.
Public Key Types
We are not interested in backwards compatibility with every existing cryptosystem. We will only tolerate a limited set of public key types.
At the outset, only Ed25519 will be supported.
In the future, we will include post-quantum digital signature algorithms on this list, but not before the current designs have had time to mature.
RSA will never be included in the set.
ECDSA over NIST P-384 may be included at some point, if there’s sufficient interest in supporting e.g., US government users.
If ECDSA is ever allowed, RFC 6979 is mandatory.
Message Processing
When an instance sends a message to a Directory Server, it will need to contain a specific marker for our protocol. Otherwise, it will be rejected.
Each message will have its own processing rules.
After the processing rules are applied, the message will be stored in the Directory Server, and a hash of the message will be published to a SigSum transparency ledger. The Merkle root and inclusion proofs will be stored in an associated record, attached to the record for the new message.
Every message will have its hash published in SigSum. No exceptions.
We will also need a mechanism for witness co-signatures to be published and attached to the record.
Additionally, all messages defined here are generated by the users, client-side. Servers are not trusted, generally, as part of the overall E2EE threat model.
AddKey
{ "@context": "https://example.com/ns/fedi-e2ee/v1", "action": "AddKey", "message": { "time": "2024-12-31T23:59:59Z", "identity": "foo@mastodon.example.com", "public-key": "ed25519:<key goes here>" }, "signature": "SignatureOfMessage"}
The first AddKey
for any given identity will need to be self-signed by the key being added (in addition to ActivityPub messages being signed by the instance).
After an identity exists in the directory, every subsequent public key MUST be signed by a non-revoked keypair.
RevokeKey
{ "@context": "https://example.com/ns/fedi-e2ee/v1", "action": "RevokeKey", "message": { "time": "2024-12-31T23:59:59Z", "identity": "foo@mastodon.example.com", "public-key": "ed25519:<key goes here>" }, "signature": "SignatureOfMessage"}
This marks the public key as untrusted, and effectively “deletes” it from the list that users will fetch.
Important: RevokeKey will fail unless there is at least one more trusted public key for this user. Otherwise, a denial of service would be possible.
Replaying an AddKey for a previously-revoked key MUST fail.
MoveIdentity
{ "@context": "https://example.com/ns/fedi-e2ee/v1", "action": "MoveIdentity", "message": { "time": "2024-12-31T23:59:59Z", "old-identity": "foo@mastodon.example.com", "new-identity": "bar@akko.example.net" }, "signature": "SignatureOfMessage"}
This exists to facilitate migrations and username changes.
Other Message Types
The above list is not exhaustive. We may need other message types depending on the exact feature set needed by the final specification.
Fetching Public Keys
A simple JSON API (and/or an ActivityStream; haven’t decided) will be exposed to query for the currently trusted public keys for a given identity.
{ "@context": "https://example.com/ns/fedi-e2ee/v1", "public-keys": [ { "data": { "time": "2024-12-31T23:59:59Z", "identity": "foo@mastodon.example.com", "public-key": "ed25519:<key goes here>" }, "signature": "SignatureOfData", "sigsum": { /* ... */ }, }, { "data": { /* ... */ }, /* ... */ }, /* ... */ ]}
Simple and easy.
Gossip Between Instances
Directory Servers should be configurable to mirror records from other instances.
Additionally, they should be configurable to serve as Witnesses for the SigSum protocol.
The communication layer here between Directory Servers will also be ActivityPub.
Preventing Abuse
The capability of learning a user’s public key doesn’t imply the ability to send messages or bypass their block list.
Additionally, Fediverse account usernames are (to my knowledge) generally not private, so I don’t anticipate there being any danger in publishing public keys to an append-only ledger.
That said, I am totally open to considering use cases where the actual identity is obfuscated (e.g., HMAC with a static key known only to the instance that hosts them instead of raw usernames).
What About GDPR / Right To Be Forgotten?
Others have previously suggested that usernames might be subject to the “right to be forgotten”, which would require breaking history for an append-only ledger.
After discussing a proposed workaround with a few people in the Signal group for this project, we realized complying necessarily introduced security issues by giving instance admins the capability of selectively remapping the user ID to different audiences, and detecting/mitigating this remapping is annoying.
However, we don’t need to do that in the first place.
According to this webpage about GDPR’s Right to be Forgotten:
However, an organization’s right to process someone’s data might override their right to be forgotten. Here are the reasons cited in the GDPR that trump the right to erasure:
- (…)
- The data is being used to perform a task that is being carried out in the public interest or when exercising an organization’s official authority.
- (…)
- The data represents important information that serves the public interest, scientific research, historical research, or statistical purposes and where erasure of the data would likely to impair or halt progress towards the achievement that was the goal of the processing.
Enabling private communication is in the public interest. The only information that will be stored in the ledger in relation to the username are cryptographic public keys, so it’s not like anything personal (e.g., email addresses or legal names) will be included.
However, we still need to be extremely up-front about this to ensure EU citizens are aware of the trade-off we’re making.
Account Recovery
In the event that a user loses access to all of their secret keys and wants to burn down the old account, they may want a way to start over with another fresh self-signed AddKey
.
However, the existing policies I wrote above would make this challenging:
- Since every subsequent
AddKey
must be signed by an incumbent key, if you don’t have access to these secret keys, you’re locked out. - Since
RevokeKey
requires one trusted keypair remains in the set, for normal operations, you can’t just burn the set down to zero even while you still had access to the secret keys.
There is an easy way out of this mess: Create a new verb; e.g. BurnDown
that an instance can issue that resets all signing keys for a given identity.
The use of BurnDown
should be a rare, exceptional event that makes a lot of noise:
- All existing E2EE sessions must break, loudly.
- All other participants must be alerted to the change, through the client software.
- Witnesses and watchdog nodes must take note of this change.
This comes with some trade-offs. Namely: Any account recovery mechanism is a backdoor, and giving the instance operators the capability of issuing BurnDown
messages is a risk to their users.
Therefore, users who trust their own security posture and wish to opt out of this recovery feature should also be able to issue a Fireproof
message at any point in the process, which permanent and irrevocably prevents any BurnDown
from being accepted on their current instance.
If users opt out of recovery and then lose their signing keys, they’re locked out and need to start over with a new Fediverse identity. On the flipside, their instance operator cannot successfully issue a BurnDown for them, so they have to trust them less.
Notice
This is just a rough sketch of my initial ideas, going into this project. It is not comprehensive, nor complete.
There are probably big gaps that need to be filled in, esp. on the ActivityPub side of things. (I’m not as worried about the cryptography side of things.)
How Will This Be Used for E2EE Direct Messaging?
I anticipate that a small pool of Directory Servers will be necessary, due to only public keys and identities being stored.
Additional changes beyond just the existence of Directory Servers will need to be made to facilitate private messaging. Some of those changes include:
- Some endpoint for users to know which Directory Servers a given ActivityPub instance federates with (if any).
- Some mechanism for users to asynchronously exchange Signed Pre-Key bundles for initiating contact. (One for users to publish new bundles, another for users to retrieve a bundle.)
- These will be Ed25519-signed payloads containing an ephemeral X25519 public key.
This is all outside the scope of the proposal I’m sketching out here today, but it’s worth knowing that I’m aware of the implementation complexity.
The important thing is: I (soatok@furry.engineer) should be able to query pawb.fun, find the Directory Server(s) they federate with, and then query that Directory server for Crashdoom@pawb.fun
and get his currently trusted Ed25519 public keys.
From there, I can query pawb.fun for a SignedPreKey bundle, which will have been signed by one of those public keys.
And then we can return to the “easy” pile.
Development Plan
Okay, so that was a lot of detail, and yet not enough detail, depending on who’s reading this blog post.
What I wrote here today is a very rough sketch. The devil is always in the details, especially with cryptography.
Goals and Non-Goals
We want Fediverse users to be able to publish a public key that is bound to their identity, which anyone else on the Internet can fetch and then use for various purposes.
We want to leverage the existing work into key transparency by the cryptography community.
We don’t want to focus on algorithm agility or protocol compatibility.
We don’t want to involve any government offices in the process. We don’t care about “real” identities, nor about codifying falsehoods about names.
We don’t want any X.509 or Web-of-Trust machinery involved in the process.
Tasks
The first thing we would need to do is write a formal specification for a Directory Server (whose job is only to vend Public Keys in an auditable, transparent manner).
Next, we need to actually build a reference implementation of this server, test it thoroughly, and then have security experts pound at the implementation for a while. Any security issues that can be mitigated by design will require a specification update.
We will NOT punt these down to implementors to be responsible for, unless we cannot avoid doing so.
Once these steps are done, we can start rolling the Directory Servers out. At this point, we can develop client-side libraries in various programming languages to make it easy for developers to adopt.
My continued work on the E2EE specification for the Fediverse can begin after we have an implementation of the Directory Server component ready to go.
Timeline
I have a very demanding couple of months ahead of me, professionally, so I don’t yet know when I can commit to starting the Fediverse Directory Server specification work.
Strictly speaking, it’s vaguely possible to get buy-in from work to focus on this project as part of my day-to-day responsibilities, since it has immediate and lasting value to the Internet.However, I don’t want to propose it because that would be crossing the professional-personal streams in a way I’m not really comfortable with.
The last thing I need is angry Internet trolls harassing my coworkers to try to get under my fur, y’know?
If there is enough interest from the broader Fediverse community, I’m also happy to delegate this work to anyone interested.
Once the work can begin, I don’t anticipate it will take more than a week for me to write a specification that other crypto nerds will take seriously.
I am confident in this because most of the cryptography will be constrained to hash functions, preventing canonicalization and cross-protocol attacks, and signatures.
Y’know, the sort of thing I write about on my furry blog for fun!
Building a reference implementation will likely take a bit longer; if, for no other reason, than I believe it would be best to write it in Go (which has the strongest SigSum support, as of this writing).
This is a lot of words to say, as far as timelines go:
How to Get Involved
Regardless of whether my overall E2EE proposal gets adopted, the Directory Server component is something that should be universally useful to the Fediverse and to software developers around the world.
If you are interested in participating in any technical capacity, I have just created a Signal Group for discussing and coordinating efforts.
All of these efforts will also be coordinated on the fedi-e2ee GitHub organization.
The public key directory server’s specification will eventually exist in this GitHub repository.
Can I Contribute Non-Technically?
Yes, absolutely. In the immediate future, once it kicks off, the work is going to be technology-oriented.
However, we may need people with non-technical skills at some point, so feel free to dive in whenever you feel comfortable.
What About Financially?
If you really have money burning a hole in your pocket and want to toss a coin my way, I do have a Ko-Fi. Do not feel pressured at all to do so, however.
Because I only use Ko-Fi as a tip jar, rather than as a business, I’m not specifically tracking which transaction is tied to which project, so I can’t make any specific promises about how any of the money sent my way will be allocated.
What I will promise, however, is that any icons/logos/etc. created for this work will be done by an artist and they will be adequately compensated for their work. I will not use large-scale computing (a.k.a., “Generative AI”) for anything.
Closing Thoughts
What I’ve sketched here is much simpler (and more ActivityPub-centric) than the collaboration I was originally planning.
Thanks for being patient while I tried, in vain, to make that work.
As of today, I no longer think we need to wait for them. We can build this ourselves, for each other.
#cryptography #endToEndEncryption #fediverse #KeyTransparency #Mastodon #MerkleTrees #PublicKeys
Everything you need to know about the “Right to be forgotten”
Also known as the right to erasure, the GDPR gives individuals the right to ask organizations to delete their personal data. But organizations don’t always have to do it....Ben Wolford (GDPR.eu)
Commission Prices for Furries and Artists
A frequent source of confusion in the furry fandom is about commission pricing for furry art.This confusion is often driven by (usually younger) furries demanding free or severely cheap art from artists, and the aftermath of such exchanges. There’s a reason @SpicyFurryTakes posts so frequently.
In the interest of not adding to the confusion, I’d like to offer a simple algorithm for artists to use for their standard commission prices, and then some guidelines for artists and commissioners to make the art commissioning experience better for everyone.
As my goal here is to simplify, I will be taking liberties and eschewing a lot of the economic details. If you feel that I made a mistake but aren’t sure because I’m not showing my work, feel free to leave a comment.
Original art by Khia, poorly edited by myself.
Commission Pricing For Artists
If you’re an artist reading this, you should almost certainly raise your rates.Furry artists in particular are notorious for undercharging for all their time and hard work. We’re talking single-digit percentages of what industry professionals charge for roughly equivalent quality.
And then when one encounters a financial emergency, they desperately scramble to take on a lot more work just to pay for whatever life event happened. If the artist hadn’t been leaving so much money on the table with their commissioners, they probably wouldn’t need to do emergency commissions in the first place–let alone endure the mental toll of delivering on them.
It’s tragic.
If you’re not sure how much you should charge at all, I recommend the following algorithm:
- Calculate your floor.
- Increase your rates.
- Are you able to consistently fill your commission slots?
- Yes -> Go to step 2 above.
- No -> Be patient.
Calculating Your Floor
Art by Swizz.
First, benchmark how long it takes you to complete a typical item on your price list. For example, a sketch of one character might take N hours to complete on average (with variance granted for complex character details).
Next, decide on a fair hourly rate for your work as a professional.
Don’t undersell yourself! For example, your hourly rate should never be less than $24 per hour (in 2020 dollars), in the United States. This number is based on what the federal minimum wage should be, if it was pinned to productivity. If that seems too high for you, don’t go below $15.
Whatever number you landed on, immediately double it. Roughly half of your income will be eaten by taxes (income taxes–including state income taxes if applicable–plus payroll taxes since you’re self-employed as an artist), unless your tax accountant tells you otherwise.
Now that you have a number in mind, you’re going to want to go through the rest of your price list and make a mental note of how many hours each item will take you to complete.
For example: If a complete illustration of one character with a detailed background takes you 8 hours, and each additional character takes an additional 2 hours, you can setup your pricing as follows:
where
is the number of additional characters beyond the first one,
is your minimum hourly rate, and
is the price of a commission.
If you decided
, then your price list entry for this type of commission might look like this:
- $400 + $100 per additional character
You should do this for every item on your commission price list.
Increase Your Rates
Once you have a price list figured out, you will want to occasionally increase your prices.
Art by Khia.
When To Increase Your Commission Prices
Generally: If you’re utilizing 100% of your allocated time for art, it’s time to increase your rates. This means you have sufficient demand to justify a price increase.If you’ve allocated 40 hours of your time per week for commission work, and you’re consistently allocating all 40 of those hours, it’s time to increase your rates.
(This logic also applies to commission “slots”, but not all slots are equal. Use your best judgment here.)
How to Increase Your Prices
There are different schools of thought on pricing strategies. As a computer programmer, my generally recommended strategy is similar to a git bisect:
- Double your prices.
- Are you able to fill at least 50% of your commission time allocation at the new prices? (Let’s call your old price N, and your new price 2N.)
- No: Go exactly halfway between the old prices and the new prices (1.5N).
- Yes: Are you able to consistently fill 100%?
- Yes: Go back to step 1. You haven’t doubled them enough.
- No: You may have found your prices, but don’t bail out just yet.
You know that 2N yields between 50% and 100% utilization. If you dropped down to 1.5N, you’d very likely see 100% utilization, so your ideal rate is probably somewhere between 1.5N and 2N.So try 1.75N.
If you’re below 50%, you need to go down (1.625N). If you hit 100%, you know you need to go up (1.875N).
Recursively iterate this process, increasing half as much as the previous step.
Keep this up until the difference between this step and the next step is smaller than some threshold (e.g. $5) or you’re at a comfortable utilization between 50% and 99%.
Working Through An Example
Let’s say you were charging $50 for sketches, $150 for lined art, and $300 for full colored illustrations, and your commission queue is always filled.First, double your prices (sketches: $50 -> $100, line art: $150 -> $300, full colored illustrations: $300 -> $600).
If your next batch of commissions gets filled to 100%: double them again (sketches are $200, line art is $600, full illustrations are $1200). Keep doing this until you’re not at 100% utilization.
If, after you’ve finished a cycle of doubling, your next batch of commissions is between 50% and 100% utilization, sit tight at your current rate. Demand for your art will increase as you grow your audience, and you’ll find yourself needing to start the process over with again.
However, if you’re at below 50% utilization, it’s time to step halfway between the old and the new. If going from the initial ($50, $150, $300) to the new ($100, $300, $600) dropped demand to below 50%, your new prices would be ($75, $225, $450). If you’re still below 50%, you can keep decreasing it further.
(Feel free to round these numbers, but err on rounding them up.)
If you started at 100% utilization, this process will end up at some price greater than your starting point.
Note:
Every time I’ve said “your prices” above, what I’m talking about are your standard rates, not what you’re offering on a particular day.You should absolutely feel entitled to offer discounts, sales, and special deals whenever it suits you.
Deeper Analysis
Computer science majors will recognize this strategy as approximately a binary search algorithm.A true binary search would zero in on your 100% utilization prices if you were capable of going above 100% utilization, but I wrote this with the assumption that 100% utilization is a market signal that you need to raise your rates. This is the guideline we’re using, because I’m assuming you cannot go above 100%. (That’s how you get burn-out!)
If you replace 100% utilization in the “true” binary search algorithm with another target percentage (say: 75%, and you bail out when you’re within 2.5% of this value), you will zero in on prices that meet your threshold.
The reason we’re increasing/decreasing by powers of 2 with each recursive iteration is that it’s the most efficient algorithm available.
A more naive approach would be to, instead of going from 2N down to 1.5N, decreasing by 0.1N until you hit your goal.
If you’re going from $100 and trying to hit a 90% utilization, and the magic number that hits that number is $147, the comparative strategies might look like this:
- $100 -> $200, 60%
- $200 -> $150, 88%
- $150 -> $125, 100%
- $125 -> $137, 100%
- $137 -> $144, 100%
- $144 -> $147, 90%
- $100 -> $200, 60%
- $200 -> $190, 65%
- $190 -> $180, 70%
- $180 -> $170, 76%
- $170 -> $160, 82%
- $160 -> $150, 88%
- $150 -> $140, 94%
backtrack, smaller increments- $140 -> $149, 88%
- $149 -> $148, 89%
- $148 -> $147, 90%
The efficiency here is important: More price changes in a short time interval can make customers nervous.In the example above, if 88% was acceptable, you could have stopped at $150. That would have been two total operations for the binary search and six for the gradual step-down approach.
In all but the most contrived scenarios, you want to use a binary search strategy.
Consider Hourly Commission Rates
Price lists have a tendency to get complicated, especially when complex character details (your fursona is a wolf, but with wings!) enter the mix.One alternative to this is, after applying the price algorithm above, simply express your prices in terms of how much time a piece of art typically takes and advertise your standard rate.
Then your commissioners will know they’re hiring you for e.g. $50/hour for a project that typically takes N hours.
Improving the Furry Art Commission Experience
Guidelines for Artists
Communicate with your commissioners. If you’re not using something like Trello to track your projects, you should send them updates more than you’d normally feel comfortable. The more complex the work, the more updates you should send.Dates Rule Everything Around Me. We understand that you have multiple projects–often running in parallel–that need to be completed to keep your clients happy. We know we’re not the only iron in your fire. Give estimate completion dates as soon as you can. If you can’t give a completion date, give an estimated date for a date. (I’m serious. This will virtually eliminate commissioner anxiety.)
Be transparent. If you need more time to get a piece done, tell your commissioners as soon as you can. Shit happens. We all get sick. We all have unproductive days/weeks. Anyone who doesn’t understand this is someone you probably want to decline accepting work from in the future.
Guidelines for Commissioners
Be polite. It’s difficult to understate how important basic manners are, even moreso when nobody seems to practice them.twitter.com/silvixenart/status…
Don’t bitch about prices. If you can’t afford their rates, you have three choices: Save up money for this luxury expense, move onto another artist, or learn to make it yourself.
n.b. This includes telling artists they should charge more! If you’re going to do that, your words must be accompanied by a generous tip. If they aren’t, you’re an asshole.
Updates are your opportunity to request changes. If you just say, “It’s coming along great, thanks for the update!” then you’re agreeing with the current direction of their work.
If the artist forgot an important detail (e.g. a marking on your fursona), the sooner you tell them, the sooner they can correct it. You aren’t being rude by informing them (unless you word it rudely; use good judgment!).
Credit your artists. Always. Link to their account too, if reasonably practical.
A lot of an artists’ income is the consequence of their previous commissioners showcasing their work. Word of mouth is the best form of advertising most can afford.
If you credit your artists, you’ll be helping them stay afloat until you decide to commission them again in the future.
Questions and Answers
Art by Khia.
I’ve received a bit of feedback since I first published this article from various sources (Reddit, forum posts in other languages that I can only hope Google Translate got right, etc.) and I thought I’d address some of your questions and concerns here.
“It takes me forever to get art done. Should I bill for my egregiously slow time?”
There are three reasons I’m aware of that could lead an artist to have a glacial work pace.
- They have insufficient art practice
- Their techniques and strategies aren’t time-efficient
- They live with some sort of disability
For the first two reasons, the solution is simply to practice more, try different techniques, and learn from other artists so you can get your work pace fast enough to earn a living from art. It’s okay if you’re still somewhat slower than your peers, but until you’re able to consistently produce art at a reasonable rate, you’re probably not ready to do art professionally (and that’s okay, not everyone has to be).
For the last one, I don’t have any useful advice. I don’t know your disability and am unqualified to advise you on what to do to overcome the challenges you face as an artist because of it. The advice on this page is intentionally very generalized and I’m sorry it won’t help you.
“My clientele only make poverty wages. How can I raise my rates without betraying them?”
I mean this in the gentlest way possible: If you’re in this situation, you do not have clients, you have friends. Friends are an incredibly good thing to have. Humanity overall severely underestimates the importance of good friendships, especially in America.But if you’re trying to earn your living through art, you have to distinguish between the two. Clients are people who–whether through income or saving up–can afford to pay you a livable wage for your time as an artist.
That isn’t to say that you can’t continue to give your friends a discount, or even free art. They’re your friends, it’s your time. Do what you will. I mentioned this above. But if you’re doing real work, you should be getting paid a real livable wage.
Your friends might even be able to help you find clients that are able and willing to pay for your time. Don’t write them off or treat them as second-class.
“This advice doesn’t apply to me because my customer base is small, or nonexistent. What now?”
There are a lot of things you can do to change this fact, but I’m not qualified to speak competently to them. (If I knew the secret to a larger social media following, don’t you think I’d have used it for myself?)Ask artists in your community for help and advice. Some might even help increase your follower counts so you can acquire more business.
“How do I find furries with sufficient disposable income to pay a livable wage?”
The truer but non-helpful answer is, “You don’t, they’ll find you.”A lot of furries that work in tech fit the bill, but not all of them. Additionally, some well-off furries are righteous assholes and you really don’t want to deal with their bullshit.
The best advice I can offer here is:
- Be active on social media.
- Be kind to people on social media.
- Don’t be afraid of self-promotion on your own feed.
Everything else boils down to patience and luck.
“I’m not an American, so what should I do differently?”
There are two schools of thought here.
- On one paw, you can localize your prices to the cost of living for your area. This will ensure your needs are met and you can comfortably continue to work as an artist in relative comfort.
- On the other paw, you could recognize that the Internet is an international marketplace and you are, at least in part, competing globally for clients. Many clients will come from wealthy countries and have the income or savings to facilitate large commissions, and therefore you can earn more money for the same work.
Use which ever you like better as your guiding light. I’m not a dictator, and even if I was, I have no mechanism to force you either way.
“What if I don’t want to make a livable wage as a furry artist, and just want to make art for other furries as a hobby?”
Why’d you click the link to this article?“What would an increased bill rate look like for an artist that followed this advice?”
See this post for a detailed breakdown of furry fandom art spending, accompanied by an analysis based on an arbitrary rate at $50/hour and utilization at 30 hours per week. (Spoiler: It ends up at about $80,000/year.)“This pricing advice isn’t specific to furry artists, it’s general pricing advice for freelancers in any industry!”
Ding ding ding!
(Art by Khia)It’s true, I didn’t invent these tactics or pull them out of a magic hat. If you’re trying to make it in the world as a professional, price your work like a professional.
From what I can gather: Roughly half of the people that read this blog post picked up on this nuance immediately. Y’all are pretty sharp.
#artists #commissions #furry #furryArtists #FurryFandom #pricing
If Worker Pay Had Kept Pace With Productivity Gains Since 1968, Today's Minimum Wage Would Be $24 an Hour
In such a world, a full-time minimum wage worker would be earning $48,000 a year in the United States.dean-baker (Common Dreams)
Fünf Jahre Covid: Keine Aufklärung und keine Aufarbeitung in China
Um den Jahreswechsel vor fünf Jahren verbreiteten sich die ersten Meldungen über eine mysteriöse Lungenkrankheit aus Wuhan in der chinesischen Provinz Hubei. Am 11. Januar meldeten die chinesischen Behörden dann den ersten Todesfall.
Kaum jemand ahnte zu Beginn, was aus der unbekannten Lungenkrankheit werden würde: eine Pandemie, die die ganze Welt Jahre lang beschäftigen würde, ausgelöst durch ein neuartiges Corona-Virus, dem die WHO später den Namen SARS-CoV 2 gab, dem Auslöser der Covid-19-Krankheit.
[...]
Bis ist heute ist ungeklärt, wo das Virus herkam. Gerüchte und Verschwörungstheorien gibt es viele.
[...]
Die chinesischen Behörden haben eine transparente und unabhängige Untersuchung durch internationale Experten nie zugelassen, was Verschwörungstheorien bis heute anheizt. In den USA hat Anfang Dezember 2024 ein von Republikanern geleitetes Parlamentskomitee einen Bericht veröffentlicht, der zu dem Schluss kam, dass das Virus aus einem Labor in Wuhan kam.
Der Sprecher des chinesischen Außenministeriums Lin Jian verurteilte den Report auf einer Pressekonferenz am 3. Dezember. Und dann drehte er den Spieß um: Die USA sollten doch erstmal selbst ihre Daten der ersten Fälle zur Verfügung stellen, an die Weltgesundheitsorganisation weitergeben und die Situation in Fort Detrick offenlegen und eine verantwortungsvolle Erklärung liefern.
Fort Detrick ist eine Militärbasis im US-Bundesstaat Maryland. Chinesische Propagandisten haben immer wieder Verschwörungstheorien verbreitet, wonach das Virus von dort aus einem Labor stammen soll. In China, wo es keine unabhängigen Medien gibt, glauben das viele.
[...]
Nach dem Ausbruch in Wuhan Ende 2019 versuchten die Behörden zunächst die Fälle zu vertuschen. Anschließend folgte ein harter Lockdown. Die Millionenstadt wurde komplett abgeriegelt, bis das Virus unter Kontrolle war.
Und dann folgten fast drei Jahre strikte Null-Covid-Politik im ganzen Land: mit weitgehend geschlossenen Grenzen, strengen Quarantäne- und Isolationsregeln, Massentests, Kontaktnachverfolgung und Lockdowns von weiteren Millionenstädten.
[...]
Als das Virus Ende 2022 nach knapp drei Jahren Null-Covid außer Kontrolle geriet, war China nicht darauf vorbereitet. Schätzungsweise eineinhalb Millionen Menschen starben innerhalb kürzester Zeit, die meisten von ihnen ältere Menschen.
In China will heute kaum jemand darüber sprechen, die Regierung will das Thema Covid vergessen machen. Experten trauen sich nicht mit ausländischen Medien zu sprechen. Die staatlich kontrollierten chinesischen Medien schweigen. Es findet keine Aufarbeitung statt in China, fünf Jahre nach dem Ausbruch von Covid-19.
Fünf Jahre Covid: Keine Aufklärung und keine Aufarbeitung in China
Auch fünf Jahre nach dem Ausbruch von Covid gibt es in China keine Aufarbeitung der eigenen Pandemie-Politik. Die Regierung will das Thema vergessen machen - und kaum jemand möchte darüber sprechen.Benjamin Eyssel (tagesschau.de)
Als ob das bei uns so viel anders wäre. Über Covid will auch hier kaum wer sprechen, eine "Nachbearbeitung" findet zumindest öffentlichkeitswirksam nicht statt.
Mein Eindruck ist, dass wir bei der nächsten Pandemie ähnlich unvorbereitet hineinstolpern.
Threema: Three Strikes, You’re Out
(If you aren’t interested in the background information, feel free to skip to the meat of this post. If you’re in a hurry, there’s a summary of results at the end.)
Around this time last year, I was writing Going Bark: A Furry’s Guide to End-to-End Encryption and the accompanying TypeScript implementation of the Extended 3-Way Diffie-Hellman authenticated key exchange (Rawr X3DH). In that blog post, I had said:
The goal of [writing] this is to increase the amount of end-to-end encryption deployed on the Internet that the service operator cannot decrypt (even if compelled by court order) and make E2EE normalized. The goal is NOT to compete with highly specialized and peer-reviewed privacy technology.
This effort had come on the heels of my analysis of bizarre choices in Zoom’s end-to-end encryption, and a brief foray into the discussion into the concept of cryptographic deniability.
I’m stating all this up-front because I want to re-emphasize that end-to-end encryption is important, and I don’t want to discourage the development of E2EE. Don’t let a critical post about someone else’s product discourage you from encrypting your users’ data.
Art: Swizz
Until recently, but especially at the time I wrote all of that, Threema had not been on my radar at all, for one simple reason: Until December 2020, Threema was not open source software.
In spite of this, Threema boasts over 1 million installs on the Google Play Store.
Partly as a result of being closed source for so long, but mostly the Threema team’s history of over-emphasizing the legal jurisdiction they operate from (Switzerland) in their claims about privacy and security, most of the cryptography experts I know had quietly put Threema in the “clown-shoes cryptography” bucket and moved on with their lives. After all, if your end-to-end encryption is well implemented and your engineers prioritized privacy with metadata collection, jurisdiction shouldn’t matter.
What changed for me was, recently, a well-meaning Twitter user mentioned Threema in response to a discussion about Signal.
twitter.com/KeijiCase/status/1…
In response, I had casually glanced through their source code and pointed out a few obvious WTFs in the Twitter thread. I had planned on following up by conducting a thorough analysis of their code and reporting my findings to them privately (which is called coordinated disclosure, not “responsible disclosure”).
But then I read this bit of FUD on their Messenger Comparison page.
Signal requires users to disclose personally identifiable information. Threema, on the other hand, can be used anonymously: Users don’t have to provide their phone number or email address. The fact that Signal, being a US-based IT service provider, is subject to the CLOUD Act only makes this privacy deficit worse.Threema – Messenger Comparison
Art: LvJ
Thus, because of their deliberate misinformation (something I’ve opposed for years), Threema has been disqualified from any such courtesy. They will see this blog post, and its contents, once it’s public and not a moment sooner.
How Are Threema’s Claims FUD?
Threema’s FUD comparison against Signal.
The quoted paragraph is deceptive, and was apparently designed to make their prospective customers distrustful of Signal.
The CLOUD Act isn’t black magic; it can only force Signal to turn over the data they actually possess. Which is, as demonstrated by a consistent paper trail of court records, almost nothing.
As usual, we couldn’t provide any of that. It’s impossible to turn over data that we never had access to in the first place. Signal doesn’t have access to your messages; your chat list; your groups; your contacts; your stickers; your profile name or avatar; or even the GIFs you search for. As a result, our response to the subpoena will look familiar. It’s the same set of “Account and Subscriber Information” that we can provide: Unix timestamps for when each account was created and the date that each account last connected to the Signal service.That’s it.
The Signal blog
Additionally, their claim that “Threema […] can be used anonymously” is, at best, a significant stretch. At worst, they’re lying by omission.
Sure, it’s possible to purchase Threema with cryptocurrency rather than using the Google Play Store. And if you assume cryptocurrency is private (n.b., the blockchain is more like tweeting all your financial transactions, unless you use something like Zcash), that probably sounds like a sweet deal.
However, even if you skip the Google Play Store, you’re constantly beaconing a device identifier to their server (which is stored on your device) whenever a license key check is initiated.
Bear in mind, over 1 million of their installed base is through the Google Play Store. This means that, in practice, almost nobody actually takes advantage of this “possibility” of anonymity.
Additionally, their own whitepaper discusses the collection of users’ phone number and email addresses. Specifically, they store hashes (really HMAC with a static, publicly known key for domain separation, but they treat it as a hash) of identifiers (mobile numbers, email addresses) on their server.
Circling back to the possibility of anonymity issue: When it comes to security (and especially cryptography), the defaults matter a lot. That’s why well-written cryptographic tools prioritize both correctness and misuse resistance over shipping new features. The default configuration is the only configuration for all but your most savvy users, because it’s the path of least resistance. Trying to take credit for the mere existence of an alternate route (bypassing the Google Play Store, paying with cryptocurrency) that few people take is dishonest, and anyone in the cryptography space should know better. It’s fine to offer that option, but not fine to emphasize it in marketing.
The only correct criticism of Signal contained within their “comparison” is that, as of this writing, they still require a phone number to bootstrap an account. The phone number requirement makes it difficult for people to have multiple independent, compartmentalized identities; i.e. preventing your professional identity from intersecting with your personal identity–which is especially not great for LGBTQIA+ folks that aren’t out to their families (usually for valid safety reasons).
This obviously sucks, but fails to justify the other claims Threema made.
With all that out of the way, let’s look at Threema’s cryptography protocol and some of their software implementations.
Art: LvJ
Threema Issues and Design Flaws
To be up front: Some of the issues and design flaws discussed below are not security vulnerabilities. Some of them are.
Where possible, I’ve included a severity rating atop each section if I believe it’s a real vulnerability, and omitted this severity rating where I believe it is not. Ultimately, a lot of what’s written here is my opinion, and you’re free to disagree with it.
List of Issues and Vulnerabilities Discovered in Threema
- Issues With Threema’s Cryptographic Protocols
- No Forward Security
- Threema IDs Aren’t Scalable
- Peer Fingerprints Aren’t Collision-Resistant
- No Breadcrumb for Cryptography Migrations
- Inconsistency with Cryptographic Randomness
- Invisible Salamanders with Group Messaging
- Issues With Threema Android (Repository)
- Weak Encryption With Master Key (LocalCrypto)
- File Encryption Uses Unauthenticated CBC Mode
- Cache-Timing Leaks with Hex-Encoding (JNaCl)
- Issues With Threema Web (Repository)
Issues With Threema’s Cryptography Protocols
This first discussion is about weaknesses in Threema’s cryptography protocol, irrespective of the underlying implementation.
At its core, Threema uses similar cryptography to Tox. This means that they’re using some version of NaCl (the library that libsodium is based on) in every implementation.
This would normally be a boring (n.b. obviously secure) choice, but the security bar for private messaging apps is very high–especially for a Signal competitor.
It isn’t sufficient for a secure messenger competing with Signal to just use NaCl. You also have to build well-designed protocols atop the APIs that NaCl gives you.
No Forward Secrecy
The goal of end-to-end encryption is to protect users from the service provider. Any security property guaranteed by transport-layer cryptography (i.e. HTTPS) are therefore irrelevant, since the cryptography is terminated on the server rather than your peer’s device.
The Threema team claims to provide forward secrecy, but only on the network connection.
Forward secrecy: Threema provides forward secrecy on the network connection (not on the end-to-end layer).
This is how Threema admits a weakness in their construction. “We offer it at a different [but irrelevant] layer.”
That’s not how any of this works.
Art: LvJ
Their whitepaper acknowledges this deficit.
As I’ve demonstrated previously, it’s not difficult to implement Signal’s X3DH AKE (which offers forward secrecy) using libsodium. Most of what I’ve done there can be done with NaCl (basically use SHA512 instead of BLAKE2b and you’re golden).
The X3DH handshake is essentially multiple Curve25519 ECDH handshakes (one long-term, one short-term e.g. biweekly, one totally ephemeral), which are mixed together using a secure key derivation function (i.e. HKDF).
To the state of the art for secure messaging that Threema claims, Forward Secrecy is table stakes. Threema’s end-to-end encryption completely lacks this property (and transport-layer doesn’t count). No amount of hand-waving on their part can make this not a weakness in Threema.
The specification for X3DH has been public for 5 years. My proof-of-concept TypeScript implementation that builds atop libsodium is nearly a year old.
If the Threema team wanted to fix this, it would not be hard for them to do so. Building a usable messaging app is much harder than building X3DH on top of a well-studied Curve25519 implementation.
Threema IDs Aren’t Scalable
Severity: Low
Impact: Denial of Service
Threema IDs are 8-digit alphanumeric unique identifiers, chosen randomly, that serve as a pseudonymous mapping to an asymmetric keypair.
This means there are possible Threema IDs (2.8 trillion). This is approximately
, so we can say there’s about a 41-bit keyspace.
That may seem like a large number (more than 100,000 the human population), but they’re chosen randomly. Which means: The birthday problem rears its ugly head.
Threema will begin to experience collisions (with 50% probability) after (roughly 1.7 million) Threema IDs have been reserved.
At first, this won’t be a problem: If you collide with someone else’s Threema ID, you just have to generate another one. That’s just an extra round-trip for the Threema server to say “LOL NO try again”. In fact, given the Google Play Store estimates for the number of Threema installs, they’re probably in excess of the birthday bound today.
Quick aside: One known problem with Threema IDs is that users don’t know they’re supposed to back them up, so when they switch phones, they lose access to their old IDs and secret keys. Aside from the obvious social engineering risk that emerges from habitually tolerating new Threema IDs for all contacts (“I lost my old Threema ID, again, so blindly trust that it’s me and not a scammer”), there’s a bigger problem.
Since Threema IDs are used by each app to identify peers, it’s not possible for Threema to recycle expired IDs. In order to do so, Threema would need to be able to inspect the social graph to determine which Threema IDs can be freed, which would be a huge privacy violation and go against their marketing.
So what happens if someone maliciously reserve-then-discards billions of Threema IDs?
Due to the pigeonhole principle, this will eventually lead to an address space exhaustion and prevent more Threema users from being onboarded. However, trouble will begin before it gets this far: At a certain point, legitimate users’ attempts to register a new Threema ID will result in an unreasonable number of contentions with reserved IDs.
Neither the Threema website nor their whitepaper discusses how Threema can cope with this sort of network strain.
Art: LvJ
This problem could have been prevented if the Threema designers were more cognizant of the birthday bound.
Additionally, the fact that Threema IDs are generated server-side is not sufficient to mitigate this risk. As long as IDs are never recycled unless explicitly deleted by their owner, they will inevitably run head-first into this problem.
Peer Fingerprints Aren’t Collision-Resistant
Severity: Informational
Impact: None
From the Threema whitepaper:
Truncating a SHA-256 hash to 128 bits doesn’t give you 128 bits of security against collision attacks. It gives you 64 bits of security, which is about the same security that SHA-1 gives you against collision attacks.
This is, once again, attributable to the birthday bound problem that affects Threema IDs.
Art: Swizz
Related: I also find it interesting that they only hash the Curve25519 public key and not the combination of public key and Threema ID. The latter construction would frustrate batch attacks by committing both the public key (which is random and somewhat opaque to users) and the Threema ID (which users see and interact with) to a given fingerprint:
- Finding a collision against a 128-bit probability space, where the input is a public key, can be leveraged against any user.
- Finding a collision against a 128-bit probability space, where the input is a public key and a given Threema ID, can only be leveraged against a targeted user (i.e. that Threema ID).
Both situations still suck because of the 128-bit truncation, but Threema managed to choose the worse of two options, and opened the door to a multi-user attack.
Impact of the Peer Fingerprint Bypass
To begin with, let’s assume the attacker has compromised all of the Threema servers and is interested in attacking the security of the end-to-end encryption. (Assuming the server is evil is table stakes for the minimum threat model for any end-to-end encrypted messaging app.)
Imagine a situation with Alice, Bob, and Dave.
Alice pushes her Threema ID and public key to the server (A_id, A_pk
), then chats with Bob legitimately (B_id, B_pk
). Bob suggests that Alice talks to his drug dealer, Dave (D_id, D_pk
).
The attacker can obtain knowledge of everyone’s public keys, and begin precomputing fingerprint collisions for any participants in the network. Their first collision will occur after keypairs are generated (with 50% probability), and then collisions will only become more frequent.
What happens when an attacker finds fingerprint collisions for people that are close on the social graph?
When Alice goes to talk with Dave, the attacker replaces her public key with one that collides with her fingerprint, but whose secret key is known to the attacker (M_pk1
). The attacker does the same thing in the opposite direction (D_id, M_pk2
).
When Alice, Bob, and Dave compare their fingerprints, they will think nothing is amiss. In reality, an attacker can silently intercept Alice’s private conversation with Dave.
The full range of key exchanges looks like this:
Alice -> Bob: (A_id, A_pk) Alice -> Dave: (A_id, M_pk1) Bob -> Alice: (B_id, B_pk) Bob -> Dave: (B_id, D_pk) Dave -> Bob: (D_id, D_pk) Dave -> Alice: (D_id, M_pk2) SHA256-128(A_pk) == SHA256-128(M_pk1), A_pk != M_pk1 SHA256-128(D_pk) == SHA256-128(M_pk2), D_pk != M_pk2
Alice will encrypt messages against M_pk2
, rather than D_pk
. But the fingerprints will match for both. Dave will respond by encrypting messages against M_pk1
, instead of A_pk
. The attacker can sit in the middle and re-encrypt messages on behalf of the recipient. Even if both Alice and Dave compare the fingerprints they see with what Bob sees, nobody will detect anything.
(Bob’s communications remain unaffected since he already downloaded everyone’s public keys. This only affects new conversations.)
This is why you only need a collision attack to violate the security of the peer fingerprint, and not a preimage attack.
To be clear, a targeted attack is much more expensive (roughly several trillion times the cost of a general attack; versus
).
This is a certificational weakness, and I’m only including it as further evidence of poor cryptographic engineering by Threema’s team rather than an overt vulnerability.
Update (2021-11-08): Remember, this is a list of issues I discovered, not specifically a list of vulnerabilities. People trying to argue in the comments, or my inbox, about whether this is “really” a vulnerability is getting a little tiring; hence, this reminder.
How to Fix Threema’s Fingerprints
First, you need to include both the Threema ID and curve25519 public key in the calculation. This will frustrate batch attacks. If they were to switch to something like X3DH, using the long-term identity key for fingerprints would also be reasonable.
Next, calculate a winder margin of truncation. here’s a handy formula to use: where
is the expected population of users. If you set equal to
, you end up with a fingerprint that truncates to 168 bits, rather than 128 bits.
This formula yields a probability space with a birthday bound of for collisions, and a preimage cost of
(even with a trillion Threema IDs reserved), which plainly isn’t going to ever happen.
No Breadcrumb for Cryptography Migrations
Severity: Informational
Impact: Frustration of Engineering Efforts
There is no concept of versioning anywhere in Threema’s protocols or designs, which means that one day migrating to better cryptography, without introducing the risk of downgrade attacks, simply isn’t possible.
The lack of any cryptography migration breadcrumb also prevents Threema from effectively mitigating security weaknesses inherent to their protocols and designs. You’ll see why this is a problem when we start looking at the implementations.
Cryptography migrations are difficult in general, because:
- Secure cryptography is not backwards compatible with insecure cryptography.
- In any distributed system, if you upgrade writers to a new cryptography protocol before your readers are upgraded too, you’ll cause availability issues.
The asynchronous nature of mobile messaging apps makes this even more challenging.
Inconsistency with Cryptographic Randomness
Severity: None
Impact: Annoyed Cryptography Auditors
Threema commits the same sin as most PGP implementations in misunderstanding the difference between /dev/random
and /dev/urandom
on Linux.
See also: Myths about /dev/urandom and How to Safely Generate a Random Number. From the latter:
Doesn’t the man page say to use /dev/random?You should ignore the man page. Don’t use /dev/random. The distinction between /dev/random and /dev/urandom is a Unix design wart. The man page doesn’t want to admit that, so it invents a security concern that doesn’t really exist. Consider the cryptographic advice in random(4) an urban legend and get on with your life.
Emphasis mine.
If you use /dev/random instead of urandom, your program will unpredictably (or, if you’re an attacker, very predictably) hang when Linux gets confused about how its own RNG works. Using /dev/random will make your programs less stable, but it won’t make them any more cryptographically safe.
Emphasis not mine.
This is an easy fix (/dev/random
-> /dev/urandom
), but it signals that the whitepaper’s author lacks awareness of cryptographic best practices.
And it turns out, they actually use /dev/urandom
in their code. So this is just an inconsistency and an annoyance rather than a flaw.
Source: UNDERTALE
Update (2021-11-08): Yes, I’m aware that the Linux RNG changed in 5.6 to make/dev/random
behave the way it always should have.However, Linux 5.6 is extremely unlikely to help anyone affected by the old Android
SecureRandom
bug that Threema has implied as part of their threat model when they called it out in their Cryptography Whitepaper, so I didn’t originally deem it fit to mention.
Invisible Salamanders with Group Messaging
Severity: Medium
Impact: Covert channel through media messages due to multi-key attacks
Note: This was discovered after the initial blog post was published and added later the same day.
Threema doesn’t do anything special (e.g. TreeKEM) for Group Messaging. Instead, groups are handled by the client and messages are encrypted directly to all parties.
This provides no group messaging authentication whatsoever. A user with a malicious Threema client can trivially join a group then send different messages to different recipients.
Imagine a group of five stock traders (A, B, C, D, E). User A posts a message to the group such that B, C, and D see “HOLD” but user E sees “SELL”.
An attacker can have some real fun with that, and it’s probably the easiest attack to pull off that I’ll discuss in this post.
User E won’t have much recourse, either: Users B, C, and D will all see a different message than User E, and will think E is dishonest. Even if User E provides a screenshot, the rest of the users will trust their own experiences with their “private messaging app” and assume User E is spinning yarns to discredit User A. It would then be very easy for A to gaslight E. This is the sort of attack that us LGBTQIA+ folks and furries are often, sadly, all too familiar with (usually from our families).
Additionally, there’s an invisible salamanders attack with media files.
Invisible Salamanders is an attack technique in systems where traditional, fast AEAD modes are employed, but more than one key can be selected. The security modes of most AEAD modes assumed one fixed symmetric encryption key held by both parties in their security designs.
To exploit the Invisible Salamanders attack:
- Generate two (or more) Xsalsa20-Poly1305 keys that will encrypt different media files to a given ciphertext + tag.
- Send a different key to a different subset of group participants.
Both parties will download the same encrypted file, but will see a different plaintext. Threema cannot detect this attack server-side to mitigate impact, either.
Art: LvJ
Encrypting multiple plaintexts, each under a different key, that produce an identical ciphertext and authentication tag is possible with AES-GCM, AES-GCM-SIV, and even Xsalsa20-Poly1305 (NaCl secretbox, which is what Threema uses).
Preventing this kind of misuse was never a security goal of these modes, and is generally not recognized as a vulnerability in the algorithms. (It would only qualify as a vulnerability if the algorithm designers stated an assumption that this violated.) However, Invisible Salamanders absolutely is a vulnerability in the protocols that build atop the algorithms. Thus, it qualifies as a vulnerability in Threema.
Here’s a Black Hat talk by Paul Grubbs explaining how the Invisible Salamanders technique works in general:
youtube.com/watch?v=3M1jIO-jLH…
This isn’t a problem for i.e. Signal, because the Double Ratchet algorithm keeps the key synchronized for all group members. Each ciphertext is signed by the sender, but encrypted with a Double Ratchet key. There’s no opportunity to convince one partition of the Group to use a different key to decrypt a message. See also: Sesame for multi-device.
The reason the vulnerability exists is that Poly1305, GMAC, etc. are fast symmetric-key message authentication algorithms, but they are not collision-resistant hash functions (e.g. SHA-256).
When you use a collision-resistant hash function, instead of a polynomial evaluation MAC, you’re getting a property called message commitment. If you use a hash function over the encryption key (and, hopefully, some domain-separation constant)–or a key the encryption key is deterministically derived from–you obtain a property called key commitment.
In either case, you can claim your AEAD mode is also random-key robust. This turns out to be true of AES-CBC + HMAC-SHA2 (what Signal uses), due to HMAC-SHA2.
Art: Scruff
Invisible Salamanders Mitigation with NaCl
First, you’ll need to split the random per-media-file key into two keys:
- A derived encryption key, which will take the place of what is currently the only key.
- A derived authentication key, which will be used with
crypto_auth
andcrypto_auth_verify
to commit the ciphertext + tag.
It’s important that both keys are derived from the same input key, and that the key derivation relies on a strong pseudorandom function.
Pseudocode:
function encryptMediaV2(data: Buffer, fileKey: Buffer) { const encKey = HmacSha256('File Encryption Key', fileKey); const authKey = HmacSha256('Media Integrity Key', fileKey); const encrypted = NaCl.crypto_secretbox(data, nonce, encKey); const commitment = NaCl.crypto_auth(encrypted, authKey); return Buffer.concat([commitment, encrypted]);}function decryptMediaV2(downloaded: Buffer, fileKey: Buffer) { const tag = downloaded.slice(0, 32); const ciphertext = downloaded.slice(32); const authKey = HmacSha256('Media Integrity Key', fileKey); if (!NaCl.crypto_auth_verify(tag, ciphertext, authKey)) { throw new Exception("bad"); } const encKey = HmacSha256('File Encryption Key', fileKey); return NaCl.crypto_secretbox_open(ciphertext, nonce, encKey);}
This code does two things:
- It derives two keys instead of only using the one. You could also just use a SHA512 hash, and then dedicate the left half to encryption and the right half to authentication. Both are fine.
- It uses the second key (not for encryption) to commit the ciphertext (encrypted file). This provides both message- and key-encryption.
If you didn’t care about message-commitment, and only cared about key-commitment, you could just skip the crypto_auth
entirely and just publish the authKey
as a public commitment hash of the key.
This corresponds to Type I in the Key Committing AEADs paper (section 3.1), if you’re trying to build a security proof.
Of course, the migration story for encrypted media in Threema is going to be challenging even if they implement my suggestion.
Issues With Threema Android
Weak Encryption with Master Key (LocalCrypto)
Severity: Low/High
Impact: Weak KDF with Crib (default) / Loss of Confidentiality (no passphrase)
The on-device protection of your Master Key (which also protects your Curve25519 secret key) consists of the following:
- A hard-coded obfuscation key (
950d267a88ea77109c50e73f47e06972dac4397c99ea7e67affddd32da35f70c
), which is XORed with the file’s contents. - (Optional) If the user sets a passphrase, calculate the PBKDF2-SHA1 of their passphrase (with only 10,000 iterations) and XOR the master key with this output.
If the user opts to not use a passphrase, if their phone is ever seized from a government agency, it might as well be stored as plaintext.
Art: LvJ
To be charitable, maybe that kind of attack is outside of their (unpublished) threat model.
Even if a user elects to store a passphrase, the low iteration count of PBKDF2 will allow for sophisticated adversaries to be able to launch offline attacks against the encrypted key file.
The 4-byte SHA1 verification checksum of the plaintext master key gives cracking code a crib for likely successful attempts (which, for weak passphrases, will almost certainly mean “you found the right key”). This is somehow worse than a typical textbook MAC-and-Encrypt design.
The checksum-as-crib is even more powerful if you’ve sent the target a photo before attempting a device seizure: Just keep trying to crack the Master Key then, after each time the checksum passes, decrypt the photo until you’ve successfully decrypted the known plaintext.
The verification checksum saves you from wasted decryption attempts; if the KDF output doesn’t produce a SHA1 hash that begins with the verification checksum, you can keep iterating until it does.
Once you’ve reproduced the file you sent in the first place, you also have their Curve25519 secret key, which means you can decrypt every message they’ve ever sent or received (especially if the Threema server operator colludes with their government).
Art: LvJ
Also, Array.equals()
isn’t constant-time. Threema should know this by now thanks to their Cure53 audit finding other examples of it a year ago. It’s 2021, you can use MessageDigest.isEqual()
for this.
Update: An Even Faster Attack Strategy
SHA1 can be expensive in a loop. A much faster technique is to do the XOR dance with the deobfuscated master key file, then see if you can decrypt the private_key
file.
Because this file is AES-CBC encrypted using the Master Key, you can just verify that the decryption result ends in a valid padding block. Because Curve25519 secret keys are 32 bytes long, there should be a full 16-byte block of PKCS#7 padding bytes when you’ve guessed the correct key.
You can then use the 4-byte SHA-1 checksum and a scalarmult vs. the target’s public key to confirm you’ve guessed the correct password.
Thanks to @Sc00bzT for pointing this attack strategy out.
File Encryption Uses Unauthenticated CBC Mode
Severity: Low
Impact: Unauthenticated encryption (but local)
Threema’s MasterKey
class has an API used elsewhere throughout the application that encrypts and decrypts files using AES/CBC/PKCS5Padding
. This mode is widely known to be vulnerable to padding oracle attacks, and has a worse wear-out story than other AES modes.
Unlike the care taken with nonces for message encryption, Threema doesn’t bother trying to keep track of which IVs it has seen before, even though a CBC collision will happen much sooner than an Xsalsa20 collision. It also just uses SecureRandom
despite the whitepaper claiming to avoid it due to weaknesses with that class on Android.
Additionally, there’s no domain separation or protection against type confusion in the methods that build atop this feature. They’re just AES-CBC-encrypted blobs that are decrypted and trusted to be the correct file format. So you can freely swap ciphertexts around and they’ll just get accepted in incorrect places.
Tangent: The Pure-Java NaCl implementation they use when JNI isn’t available also uses SecureRandom
. If you’re going to include a narrative in your Cryptography Whitepaper, maybe check that you’re consistently adhering to it?
Cache-Timing Leaks with Hex-Encoding (JNaCl)
Severity: Low
Impact: Information disclosure through algorithm time
This isn’t a meaningfully practical risk, but it’s still disappointing to see in their pure-Java NaCl implementation. Briefly:
- JNaCl definition for hex-encoding and decoding
- OpenJDK definition for
[url=https://github.com/openjdk/jdk/blob/739769c8fc4b496f08a92225a12d07414537b6c0/src/java.base/share/classes/java/lang/Character.java#L10660-L10662]Character.digit()[/url]
- OpenJDK definition for
[url=https://github.com/openjdk/jdk/blob/739769c8fc4b496f08a92225a12d07414537b6c0/make/data/characterdata/CharacterDataLatin1.java.template#L196]CharacterDataLatin1.digit()[/url]
Because this implementation uses table lookups, whenever a secret (plaintext or key) goes through one of the JNaCl hexadecimal functions, it will leak the contents of the secret through cache-timing.
For reference, here’s how libsodium implements hex-encoding and decoding.
Art: Swizz
Issues With Threema Web
I’m not going to spend a lot of time on the Threema Web project, since it’s been in maintenance-only mode since at least January.
Insecure Password-Based Key Derivation
Severity: High
Impact: Insecure cryptographic storage
While SHA512 is a good cryptographic hash function, it’s not a password hash function. Those aren’t the same thing.
Threema’s Web client derives the keystore encryption key from a password by using the leftmost 32 bytes of a SHA512 hash of the password.
/** * Convert a password string to a NaCl key. This is done by getting a * SHA512 hash and returning the first 32 bytes. */private pwToKey(password: string): Uint8Array { const bytes = this.stringToBytes(password); const hash = nacl.hash(bytes); return hash.slice(0, nacl.secretbox.keyLength);}
Once again, just because you’re using NaCl, doesn’t mean you’re using it well.
This code opens the door to dictionary attacks, rainbow tables, accelerated offline attacks, and all sorts of other nasty scenarios that would have been avoided if a password hashing algorithm was used instead of SHA512.
Also, this is another cache-timing leak in most JavaScript engines and the entire method that contains it could have been replaced by Uint8Array.from(password, 'utf-8')
.
Threema can’t claim they were avoiding the UInt8Array.from()
method there because of compatibility concerns (e.g. with IE11) because they use it here.
Art: LvJ
Summary of Results
In the cryptography employed by Threema, I was able to quickly identify 5 6 issues, of which 2 3 directly negatively impact the security of their product (Threema IDs Aren’t Scalable can lead to address exhaustion and Denial-of-Service; Peer Fingerprints Aren’t Collision-Resistant allows moderately-funded adversaries to bypass fingerprint detection for a discount).
Both security issues in the Threema cryptography protocol were caused by a poor understanding of the birthday bound of a pseudorandom function–something that’s adequately covered by Dan Boneh’s Cryptography I course.
Additionally, the total lack of forward secrecy invalidates the Threema marketing claims of being more private or secure than Signal.
Update (3:45 PM): After initially publishing this, I realized there was a third security issue in the cryptography protocol, concerning Group Messaging: Invisible Salamanders.
In the Android app, I was able to identify 3 issues, of which 2 directly negatively impact the security of their product (Weak Encryption With Master Key (LocalCrypto) provides a very weak obfuscation or somewhat weak KDF (with a checksum) that, either way, makes leaking the key easier than it should be; File Encryption Uses Unauthenticated CBC Mode introduces all of the problems of CBC mode and unauthenticated encryption).
Finally, I only identified 1 security issue in the web client (Insecure Password-Based Key Derivation) before I saw the maintenance notice in the README on GitHub and decided it’s not worth my time to dive any deeper.
I did not study the iOS app at all. Who knows what dragons there be?
Art: LvJ
There were a few other issues that I thought existed, and later realized was false. For example: At first glance, it looked like they weren’t making sure received messages didn’t collide with an existing nonce (n.b. only on messages being sent)–which, since the same key is used in both directions, would be catastrophic. It turns out, they do store the nonces on received messages, so a very obvious attack isn’t possible.
The fact that Threema’s developers built atop NaCl probably prevented them from implementing higher-severity issues in their product. Given that Threema Web finding, I can’t help but ponder if they would have been better served by libsodium instead of NaCl.
Threema has been publicly audited (twice!) by vendors that they hired to perform code audits, and yet so many amateur cryptography mistakes persist in their designs and implementations years later. From their most recent audit:
Cure53’s conclusion doesn’t jive with my observations. I don’t know if that says something about them, or something about me, or even something much more meta and existential about the nature of cryptographic work.
Art: Riley
Is Threema Vulnerable to Attack?
Unfortunately, yes. In only a few hours of review, I was able to identify 3 vulnerabilities in Threema’s cryptography, as well as 3 others affecting their Android and web apps.
How Severe Are These Issues?
While there are several fundamental flaws in Threema’s overall cryptography, they mostly put the service operators at risk and signal a lack of understanding of the basics of cryptography. (Namely: discrete probability and pseudorandom functions.)
The biggest and most immediate concern for Threema users is that a malicious user can send different media messages to different members of the same group, and no one can detect the deception. This is a much easier attack to pull off than anything else discussed above, and can directly be used to sew confusion and enable gaslighting.
For Threema Enterprise users, imagine someone posting a boring document in a group chat for work purposes, while also covertly leaking confidential and proprietary documents to someone that’s not supposed to have access to said documents. Even though you all see the same encrypted file, the version you decrypt is very different from what’s being fed to the leaker. Thus, Threema’s vulnerability offers a good way for insider threats to hide their espionage in plain sight.
The remaining issues discussed do not put anyone at risk, and are just uncomfortable design warts in Threema.
Recommendations for Threema Users
Basically, I don’t recommend Threema.
Art: LvJ
Most of what I shared here isn’t a game over vulnerability, provided you aren’t using Threema for group messaging, but my findings certainly debunk the claims made by Threema’s marketing copy.
If you are using Threema for group messaging–and especially for sharing files–you should be aware of the Invisible Salamanders attack discussed above.
When in doubt, just use Signal. It’s free, open source, private, and secure.
The reason you hear less about Signal on blogs like this is because, when people like me reviews their code, we don’t find these sorts of problems. I’ve tried to find problems before.
If you want a federated, desktop-first experience with your end-to-end encryption without a phone number, I don’t have any immediate replacement recommendations. Alternatives exist, but there’s no clear better option that’s production-ready today.
If you want all of the above and mobile support too, with Tor support as a first-class feature enabled by default, Open Privacy is developing Cwtch. It’s still beta software, though, and doesn’t support images or video yet. You also can’t install it through the Google Play Store (although that will probably change when they’re out of beta).
Looking forward, Signal recently announced the launch of anti-spam and spam-reporting features. This could indicate that the phone number requirement could be vanishing soon. (They already have a desktop client, after all.) If that happens, I implore everyone to ditch Threema immediately.
Disclosure Timeline
This is all zero-day. I did not notify Threema ahead of time with these findings.
Threema talks a big talk–calling themselves more private/secure than Signal and spreading FUD instead of an honest comparison.
If you’re going to engage in dishonest behavior, I’m going to treat you the same way I treat other charlatans. Especially when your dishonesty will deceive users into trusting an inferior product with their most sensitive and intimate conversations.
Threema also like to use the term “responsible disclosure” (which is a term mostly used by vendors to gaslight security researchers into thinking full disclosure is unethical) instead of the correct term (coordinated disclosure).
Additionally, in cryptography, immediate full disclosure is preferred over coordinated disclosure or non-disclosure. The responsibility of a security engineer is to protect the users, not the vendors, so in many cases, full disclosure is responsible disclosure.
twitter.com/ThreemaApp/status/…
That’s just a pet peeve of mine, though. Can we please dispense of this paleologism?
If you’re curious about the title, Threema’s three strikes were:
- Arrogance (claiming to be more private than Signal)
- Dishonesty (attempting to deceive their users about Signal’s privacy compared with Threema)
- Making amateur mistakes in their custom cryptography designs (see: everything I wrote above this section)
#cryptography #OnlinePrivacy #privacy #privateMessaging #symmetricCryptography #Threema #vuln #ZeroDay
Remove the need for a mobile phone
Hello! Wire also requires a mobil number for registration, or, if you do it via the webpage, an e-mail address. From week to week I start to like the approach of Wickr. Just chose a username, choose a password, and no registration process.Signal Community
Going Bark: A Furry’s Guide to End-to-End Encryption
Governments are back on their anti-encryption bullshit again.Between the U.S. Senate’s “EARN IT” Act, the E.U.’s slew of anti-encryption proposals, and Australia’s new anti-encryption law, it’s become clear that the authoritarians in office view online privacy as a threat to their existence.
Normally, when the governments increase their anti-privacy sabre-rattling, technologists start talking more loudly about Tor, Signal, and other privacy technologies (usually only to be drowned out by paranoid people who think Tor and Signal are government backdoors or something stupid; conspiracy theories ruin everything!).
I’m not going to do that.
Instead, I’m going to show you how to add end-to-end encryption to any communication software you’re developing. (Hopefully, I’ll avoid making any bizarre design decisions along the way.)
But first, some important disclaimers:
- Yes, you should absolutely do this. I don’t care how banal your thing is; if you expect people to use it to communicate with each other, you should make it so that you can never decrypt their communications.
- You should absolutely NOT bill the thing you’re developing as an alternative to Signal or WhatsApp.
- The goal of doing this is to increase the amount of end-to-end encryption deployed on the Internet that the service operator cannot decrypt (even if compelled by court order) and make E2EE normalized. The goal is NOT to compete with highly specialized and peer-reviewed privacy technology.
- I am not a lawyer, I’m some furry who works in cryptography. The contents of this blog post is not legal advice, nor is it endorsed by any company or organization. Ask the EFF for legal questions.
The organization of this blog post is as follows: First, I’ll explain how to encrypt and decrypt data between users, assuming you have a key. Next, I’ll explain how to build an authenticated key exchange and a ratcheting protocol to determine the keys used in the first step. Afterwards, I’ll explore techniques for binding authentication keys to identities and managing trust. Finally, I’ll discuss strategies for making it impractical to ever backdoor your software (and impossible to silently backdoor it), just to piss the creeps and tyrants of the world off even more.
You don’t have to implement the full stack of solutions to protect users, but the further you can afford to go, the safer your users will be from privacy-invasive policing.
(Art by Kyume.)
Preliminaries
Choosing a Cryptography Library
In the examples contained on this page, I will be using the Sodium cryptography library. Specifically, my example code will be written with the Sodium-Plus library for JavaScript, since it strikes a good balance between performance and being cross-platform.const { SodiumPlus } = require('sodium-plus');(async function() { // Select a backend automatically const sodium = await SodiumPlus.auto(); // Do other stuff here})();
Libsodium is generally the correct choice for developing cryptography features in software, and is available in most programming languages,
If you’re prone to choose a different library, you should consult your cryptographer (and yes, you should have one on your payroll if you’re doing things different) about your design choices.
Threat Modelling
Remember above when I said, “You don’t have to implement the full stack of solutions to protect users, but the further you can afford to go, the safer your users will be from privacy-invasive policing”?How far you go in implementing the steps outlined on this blog post should be informed by a threat model, not an ad hoc judgment.
For example, if you’re encrypting user data and storing it in the cloud, you probably want to pass the Mud Puddle Test:
1. First, drop your device(s) in a mud puddle.
2. Next, slip in said puddle and crack yourself on the head. When you regain consciousness you’ll be perfectly fine, but won’t for the life of you be able to recall your device passwords or keys.
3. Now try to get your cloud data back.Did you succeed? If so, you’re screwed. Or to be a bit less dramatic, I should say: your cloud provider has access to your ‘encrypted’ data, as does the government if they want it, as does any rogue employee who knows their way around your provider’s internal policy checks.
Matthew Green describes the Mud Puddle Test, which Apple products definitely don’t pass.
If you must fail the Mud Puddle Test for your users, make sure you’re clear and transparent about this in the documentation for your product or service.
(Art by Swizz.)
I. Symmetric-Key Encryption
The easiest piece of this puzzle is to encrypt data in transit between both ends (thus, satisfying the loosest definition of end-to-end encryption).At this layer, you already have some kind of symmetric key to use for encrypting data before you send it, and for decrypting it as you receive it.
For example, the following code will encrypt/decrypt strings and return hexadecimal strings with a version prefix.
const VERSION = "v1";/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function encryptData(message, key, assocData = null) { const nonce = await sodium.randombytes_buf(24); const aad = JSON.stringify({ 'version': VERSION, 'nonce': await sodium.sodium_bin2hex(nonce), 'extra': assocData }); const encrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt( message, nonce, key, aad ); return ( VERSION + await sodium.sodium_bin2hex(nonce) + await sodium.sodium_bin2hex(encrypted) );}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function decryptData(encrypted, key, assocData = null) { const ver = encrypted.slice(0, 2); if (!await sodium.sodium_memcmp(ver, VERSION)) { throw new Error("Incorrect version: " + ver); } const nonce = await sodium.sodium_hex2bin(encrypted.slice(2, 50)); const ciphertext = await sodium.sodium_hex2bin(encrypted.slice(50)); const aad = JSON.stringify({ 'version': ver, 'nonce': encrypted.slice(2, 50), 'extra': assocData }); const plaintext = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( ciphertext, nonce, key, aad ); return plaintext.toString('utf-8');}
Under-the-hood, this is using XChaCha20-Poly1305, which is less sensitive to timing leaks than AES-GCM. However, like AES-GCM, this encryption mode doesn’t provide message- or key-commitment.
If you want key commitment, you should derive two keys from
$key
using a KDF based on hash functions: One for actual encryption, and the other as a key commitment value.If you want message commitment, you can use AES-CTR + HMAC-SHA256 or XChaCha20 + BLAKE2b-MAC.
If you want both, ask Taylor Campbell about his BLAKE3-based design.
A modified version of the above code with key-commitment might look like this:
const VERSION = "v2";/** * Derive an encryption key and a commitment hash. * @param {CryptographyKey} key * @param {Uint8Array} nonce * @returns {{encKey: CryptographyKey, commitment: Uint8Array}} */async function deriveKeys(key, nonce) { const encKey = new CryptographyKey(await sodium.crypto_generichash( new Uint8Array([0x01].append(nonce)), key )); const commitment = await sodium.crypto_generichash( new Uint8Array([0x02].append(nonce)), key ); return {encKey, commitment};}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function encryptData(message, key, assocData = null) { const nonce = await sodium.randombytes_buf(24); const aad = JSON.stringify({ 'version': VERSION, 'nonce': await sodium.sodium_bin2hex(nonce), 'extra': assocData }); const {encKey, commitment} = await deriveKeys(key, nonce); const encrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt( message, nonce, encKey, aad ); return ( VERSION + await sodium.sodium_bin2hex(nonce) + await sodium.sodium_bin2hex(commitment) + await sodium.sodium_bin2hex(encrypted) );}/** * @param {string|Uint8Array} message * @param {Uint8Array} key * @param {string|null} assocData * @returns {string} */async function decryptData(encrypted, key, assocData = null) { const ver = encrypted.slice(0, 2); if (!await sodium.sodium_memcmp(ver, VERSION)) { throw new Error("Incorrect version: " + ver); } const nonce = await sodium.sodium_hex2bin(encrypted.slice(2, 50)); const ciphertext = await sodium.sodium_hex2bin(encrypted.slice(114)); const aad = JSON.stringify({ 'version': ver, 'nonce': encrypted.slice(2, 50), 'extra': assocData }); const storedCommitment = await sodium.sodium_hex2bin(encrypted.slice(50, 114)); const {encKey, commitment} = await deriveKeys(key, nonce); if (!(await sodium.sodium_memcmp(storedCommitment, commitment))) { throw new Error("Incorrect commitment value"); } const plaintext = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( ciphertext, nonce, encKey, aad ); return plaintext.toString('utf-8');}
Another design choice you might make is to encode ciphertext with base64 instead of hexadecimal. That doesn’t significantly alter the design here, but it does mean your decoding logic has to accommodate this.
You SHOULD version your ciphertexts, and include this in the AAD provided to your AEAD encryption mode. I used “v1” and “v2” as a version string above, but you can use your software name for that too.
II. Key Agreement
If you’re not familiar with Elliptic Curve Diffie-Hellman or Authenticated Key Exhcanges, the two of the earliest posts on this blog were dedicated to those topics.Key agreement in libsodium uses Elliptic Curve Diffie-Hellman over Curve25519, or X25519 for short.
There are many schools of thought for extending ECDH into an authenticated key exchange protocol.
We’re going to implement what the Signal Protocol calls X3DH instead of doing some interactive EdDSA + ECDH hybrid, because X3DH provides cryptographic deniability (see this section of the X3DH specification for more information).
For the moment, I’m going to assume a client-server model. That may or may not be appropriate for your design. You can substitute “the server” for “the other participant” in a peer-to-peer configuration.
Head’s up: This section of the blog post is code-heavy.
Update (November 23, 2020): I implemented this design in TypeScript, if you’d like something tangible to work with. I call my library, Rawr X3DH.
X3DH Pre-Key Bundles
Each participant will need to upload an Ed25519 identity key once (which is a detail covered in another section), which will be used to sign bundles of X25519 public keys to use for X3DH.Your implementation will involve a fair bit of boilerplate, like so:
/** * Generate an X25519 keypair. * * @returns {{secretKey: X25519SecretKey, publicKey: X25519PublicKey}} */async function generateKeyPair() { const keypair = await sodium.crypto_box_keypair(); return { secretKey: await sodium.crypto_box_secretkey(keypair), publicKey: await sodium.crypto_box_publickey(keypair) };}/** * Generates some number of X25519 keypairs. * * @param {number} preKeyCount * @returns {{secretKey: X25519SecretKey, publicKey: X25519PublicKey}[]} */async function generateBundle(preKeyCount = 100) { const bundle = []; for (let i = 0; i < preKeyCount; i++) { bundle.push(await generateKeyPair()); } return bundle;}/** * BLAKE2b( len(PK) | PK_0, PK_1, ... PK_n ) * * @param {X25519PublicKey[]} publicKeys * @returns {Uint8Array} */async function prehashPublicKeysForSigning(publicKeys) { const hashState = await sodium.crypto_generichash_init(); // First, update the state with the number of public keys const pkLen = new Uint8Array([ (publicKeys.length >>> 24) & 0xff, (publicKeys.length >>> 16) & 0xff, (publicKeys.length >>> 8) & 0xff, publicKeys.length & 0xff ]); await sodium.crypto_generichash_update(hashState, pkLen); // Next, update the state with each public key for (let pk of publicKeys) { await sodium.crypto_generichash_update( hashState, pk.getBuffer() ); } // Return the finalized BLAKE2b hash return await sodium.crypto_generichash_final(hashState);}/** * Signs a bundle. Returns the signature. * * @param {Ed25519SecretKey} signingKey * @param {X25519PublicKey[]} publicKeys * @returns {Uint8Array} */async function signBundle(signingKey, publicKeys) { return sodium.crypto_sign_detached( await prehashPublicKeysForSigning(publicKeys), signingKey );}/** * This is just so you can see how verification looks. * * @param {Ed25519PublicKey} verificationKey * @param {X25519PublicKey[]} publicKeys * @param {Uint8Array} signature */async function verifyBundle(verificationKey, publicKeys, signature) { return sodium.crypto_sign_verify_detached( await prehashPublicKeysForSigning(publicKeys), verificationKey, signature );}
This boilerplate exists just so you can do something like this:
/** * Generate some number of X25519 keypairs. * Persist the bundle. * Sign the bundle of publickeys with the Ed25519 secret key. * Return the signed bundle (which can be transmitted to the server.) * * @param {Ed25519SecretKey} signingKey * @param {number} numKeys * @returns {{signature: string, bundle: string[]}} */async function x3dh_pre_key(signingKey, numKeys = 100) { const bundle = await generateBundle(numKeys); const publicKeys = bundle.map(x => x.publicKey); const signature = await signBundle(signingKey, publicKeys); // This is a stub; how you persist it is app-specific: persistBundleNotDefinedHere(signingKey, bundle); // Hex-encode all the public keys const encodedBundle = []; for (let pk of publicKeys) { encodedBundle.push(await sodium.sodium_bin2hex(pk.getBuffer())); } return { 'signature': await sodium.sodium_bin2hex(signature), 'bundle': encodedBundle };}
And then you can drop the output of
x3dh_pre_key(secretKey)
into a JSON-encoded HTTP request.In accordance to Signal’s X3DH spec, you want to use
x3dh_pre_key(secretKey, 1)
to generate the “signed pre-key” bundle andx3dn_pre_key(secretKey, 100)
when pushing 100 one-time keys to the server.X3DH Initiation
This section conforms to the Sending the Initial Message section of the X3DH specification.When you initiate a conversation, the server should provide you with a bundle containing:
- Your peer’s Identity key (an Ed25519 public key)
- Your peer’s current Signed Pre-Key (an X25519 public key)
- (If any remain unburned) One of your key’s One-Time Keys (an X25519 public key) — and then delete it
If we assume the structure of this response looks like this:
{ "IdentityKey": "...", "SignedPreKey": { "Signature": "..." "PreKey": "..." }, "OneTimeKey": "..." // or NULL}
Then we can write the initiation step of the handshake like so:
/** * Get SK for initializing an X3DH handshake * * @param {object} r -- See previous code block * @param {Ed25519SecretKey} senderKey */async function x3dh_initiate_send_get_sk(r, senderKey) { const identityKey = new Ed25519PublicKey( await sodium.sodium_hex2bin(r.IdentityKey) ); const signedPreKey = new X25519PublicKey( await sodium.sodium_hex2bin(r.SignedPreKey.PreKey) ); const signature = await sodium.sodium_hex2bin(r.SignedPreKey.Signature); // Check signature const valid = await verifyBundle(identityKey, [signedPreKey], signature); if (!valid) { throw new Error("Invalid signature"); } const ephemeral = await generateKeyPair(); const ephSecret = ephemeral.secretKey; const ephPublic = ephemeral.publicKey; // Turn the Ed25519 keys into X25519 keys for X3DH: const senderX = await sodium.crypto_sign_ed25519_sk_to_curve25519(senderKey); const recipientX = await sodium.crypto_sign_ed25519_pk_to_curve25519(identityKey); // See the X3DH specification to really understand this part: const DH1 = await sodium.crypto_scalarmult(senderX, signedPreKey); const DH2 = await sodium.crypto_scalarmult(ephSecret, recipientX); const DH3 = await sodium.crypto_scalarmult(ephSecret, signedPreKey); let SK; if (r.OneTimeKey) { let DH4 = await sodium.crypto_scalarmult( ephSecret, new X25519PublicKey(await sodium.sodium_hex2bin(r.OneTimeKey)) ); SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) .concat(DH4.getBuffer()) )); DH4.wipe(); } else { SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) )); } // Wipe keys DH1.wipe(); DH2.wipe(); DH3.wipe(); ephSecret.wipe(); senderX.wipe(); return { IK: identityKey, EK: ephPublic, SK: SK, OTK: r.OneTimeKey // might be NULL };}/** * Initialize an X3DH handshake * * @param {string} recipientIdentity - Some identifier for the user * @param {Ed25519SecretKey} secretKey - Sender's secret key * @param {Ed25519PublicKey} publicKey - Sender's public key * @param {string} message - The initial message to send * @returns {object} */async function x3dh_initiate_send(recipientIdentity, secretKey, publicKey, message) { const r = await get_server_response(recipientIdentity); const {IK, EK, SK, OTK} = await x3dh_initiate_send_get_sk(r, secretKey); const assocData = await sodium.sodium_bin2hex( new Uint8Array( [].concat(publicKey.getBuffer()) .concat(IK.getBuffer()) ) ); /* * We're going to set the session key for our recipient to SK. * This might invoke a ratchet. * * Either SK or the output of the ratchet derived from SK * will be returned by getEncryptionKey(). */ await setSessionKey(recipientIdentity, SK); const encrypted = await encryptData( message, await getEncryptionKey(recipientIdentity), assocData ); return { "Sender": my_identity_string, "IdentityKey": await sodium.sodium_bin2hex(publicKey), "EphemeralKey": await sodium.sodium_bin2hex(EK), "OneTimeKey": OTK, "CipherText": encrypted };}
We didn’t define
setSessionKey()
orgetEncryptionKey()
above. It will be covered later.X3DH – Receiving an Initial Message
This section implements the Receiving the Initial Message section of the X3DH Specification.We’re going to assume the structure of the request looks like this:
{ "Sender": "...", "IdentityKey": "...", "EphemeralKey": "...", "OneTimeKey": "...", "CipherText": "..."}
The code to handle this should look like this:
/** * Handle an X3DH initiation message as a receiver * * @param {object} r -- See previous code block * @param {Ed25519SecretKey} identitySecret * @param {Ed25519PublicKey} identityPublic * @param {Ed25519SecretKey} preKeySecret */async function x3dh_initiate_recv_get_sk( r, identitySecret, identityPublic, preKeySecret) { // Decode strings const senderIdentityKey = new Ed25519PublicKey( await sodium.sodium_hex2bin(r.IdentityKey), ); const ephemeral = new X25519PublicKey( await sodium.sodium_hex2bin(r.EphemeralKey), ); // Ed25519 -> X25519 const senderX = await sodium.crypto_sign_ed25519_pk_to_curve25519(senderIdentityKey); const recipientX = await sodium.crypto_sign_ed25519_sk_to_curve25519(identitySecret); // See the X3DH specification to really understand this part: const DH1 = await sodium.crypto_scalarmult(preKeySecret, senderX); const DH2 = await sodium.crypto_scalarmult(recipientX, ephemeral); const DH3 = await sodium.crypto_scalarmult(preKeySecret, ephemeral); let SK; if (r.OneTimeKey) { let DH4 = await sodium.crypto_scalarmult( await fetchAndWipeOneTimeSecretKey(r.OneTimeKey), ephemeral ); SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) .concat(DH4.getBuffer()) )); DH4.wipe(); } else { SK = kdf(new Uint8Array( [].concat(DH1.getBuffer()) .concat(DH2.getBuffer()) .concat(DH3.getBuffer()) )); } // Wipe keys DH1.wipe(); DH2.wipe(); DH3.wipe(); recipientX.wipe(); return { Sender: r.Sender, SK: SK, IK: senderIdentityKey };}/** * Initiate an X3DH handshake as a recipient * * @param {object} req - Request object * @returns {string} - The initial message */async function x3dh_initiate_recv(req) { const {identitySecret, identityPublic} = await getIdentityKeypair(); const {preKeySecret, preKeyPublic} = await getPreKeyPair(); const {Sender, SK, IK} = await x3dh_initiate_recv_get_sk( req, identitySecret, identityPublic, preKeySecret, preKeyPublic ); const assocData = await sodium.sodium_bin2hex( new Uint8Array( [].concat(IK.getBuffer()) .concat(identityPublic.getBuffer()) ) ); try { await setSessionKey(senderIdentity, SK); return decryptData( req.CipherText, await getEncryptionKey(senderIdentity), assocData ); } catch (e) { await destroySessionKey(senderIdentity); throw e; }}
And with that, you’ve successfully implemented X3DH and symmetric encryption in JavaScript.
We abstracted some of the details away (i.e.
kdf()
, the transport mechanisms, the session key management mechanisms, and a few others). Some of them will be highly specific to your application, so it doesn’t make a ton of sense to flesh them out.One thing to keep in mind: According to the X3DH specification, participants should regularly (e.g. weekly) replace their Signed Pre-Key in the server with a fresh one. They should also publish more One-Time Keys when they start to run low.
If you’d like to see a complete reference implementation of X3DH, as I mentioned before, Rawr-X3DH implements it in TypeScript.
Session Key Management
Using X3DH to for every message is inefficient and unnecessary. Even the Signal Protocol doesn’t do that.Instead, Signal specifies a Double Ratchet protocol that combines a Symmetric-Key Ratchet on subsequent messages, and a Diffie-Hellman-based ratcheting protocol.
Signal even specifies integration guidelines for the Double Ratchet with X3DH.
It’s worth reading through the specification to understand their usages of Key-Derivation Functions (KDFs) and KDF Chains.
Although it is recommended to use HKDF as the Signal protocol specifies, you can strictly speaking use any secure keyed PRF to accomplish the same goal.
What follows is an example of a symmetric KDF chain that uses BLAKE2b with 512-bit digests of the current session key; the leftmost half of the BLAKE2b digest becomes the new session key, while the rightmost half becomes the encryption key.
const SESSION_KEYS = {};/** * Note: In reality you'll want to have two separate sessions: * One for receiving data, one for sending data. * * @param {string} identity * @param {CryptographyKey} key */async function setSessionKey(identity, key) { SESSION_KEYS[identity] = key;}async function getEncryptionKey(identity) { if (!SESSION_KEYS[identity]) { throw new Error("No session key for " + identity"); } const blake2bMac = await sodium.crypto_generichash( SESSION_KEYS[identity], null, 64 ); SESSION_KEYS[identity] = new CryptographyKey(blake2bMac.slice(0, 32)); return new CryptographyKey(blake2bMac.slice(32, 64));}
In the interest of time, a full DHRatchet implementation is left as an exercise to the reader (since it’s mostly a state machine), but using the appropriate functions provided by sodium-plus (
crypto_box_keypair()
,crypto_scalarmult()
) should be relatively straightforward.Make sure your KDFs use domain separation, as per the Signal Protocol specifications.
Group Key Agreement
The Signal Protocol specified X3DH and the Double Ratchet for securely encrypting information between two parties.Group conversations are trickier, because you have to be able to encrypt information that multiple recipients can decrypt, add/remove participants to the conversation, etc.
(The same complexity comes with multi-device support for end-to-end encryption.)
The best design I’ve read to date for tackling group key agreement is the IETF Messaging Layer Security RFC draft.
I am not going to implement the entire MLS RFC in this blog post. If you want to support multiple devices or group conversations, you’ll want a complete MLS implementation to work with.
Brief Recap
That was a lot of ground to cover, but we’re not done yet.
(Art by Khia.)
So far we’ve tackled encryption, initial key agreement, and session key management. However, we did not flesh out how Identity Keys (which are signing keys–Ed25519 specifically–rather than Diffie-Hellman keys) are managed. That detail was just sorta hand-waved until now.
So let’s talk about that.
III. Identity Key Management
There’s a meme among technology bloggers to write a post titled “Falsehoods Programmers Believe About _____”.Fortunately for us, Identity is one of the topics that furries are positioned to understand better than most (due to fursonas): Identities have a many-to-many relationship with Humans.
In an end-to-end encryption protocol, each identity will consist of some identifier (phone number, email address, username and server hostname, etc.) and an Ed25519 keypair (for which the public key will be published).
But how do you know whether or not a given public key is correct for a given identity?
This is where we segue into one of the hard problems in cryptography, where the solutions available are entirely dependent on your threat model: Public Key Infrastructure (PKI).
Some common PKI designs include:
- Certificate Authorities (CAs) — TLS does this
- Web-of-Trust (WoT) — The PGP ecosystem does this
- Trust On First Use (TOFU) — SSH does this
- Key Transparency / Certificate Transparency (CT) — TLS also does this for ensuring CA-issued certificates are auditable (although it was originally meant to replace Certificate Authorities)
And you can sort of choose-your-own-adventure on this one, depending on what’s most appropriate for the type of software you’re building and who your customers are.
One design I’m particularly fond of is called Gossamer, which is a PKI design without Certificate Authorities, originally designed for making WordPress’s automatic updates more secure (i.e. so every developer can sign their theme and plugin updates).
Since we only need to maintain an up-to-date repository of Ed25519 identity keys for each participant in our end-to-end encryption protocol, this makes Gossamer a suitable starting point.
Gossamer specifies a limited grammar of Actions that can be performed: AppendKey, RevokeKey, AppendUpdate, RevokeUpdate, and AttestUpdate. These actions are signed and published to an append-only cryptographic ledger.
I would propose a sixth action: AttestKey, so you can have WoT-like assurances and key-signing parties. (If nothing else, you should be able to attest that the identity keys of other cryptographic ledgers in the network are authentic at a point in time.)
IV. Backdoor Resistance
In the previous section, I proposed the use of Gossamer as a PKI for Identity Keys. This would provide Ed25519 keypairs for use with X3DH and the Double Ratchet, which would in turn provide session keys to use for symmetric authenticated encryption.If you’ve implemented everything preceding this section, you have a full-stack end-to-end encryption protocol. But let’s make intelligence agencies and surveillance capitalists even more mad by making it impractical to backdoor our software (and impossible to silently backdoor it).
How do we pull that off?
You want Binary Transparency.
For us, the implementation is simple: Use Gossamer as it was originally intended (i.e. to secure your software distribution channels).
Gossamer provides up-to-date verification keys and a commitment to a cryptographic ledger of every software update. You can learn more about its inspiration here.
It isn’t enough to merely use Gossamer to manage keys and update signatures. You need independent third parties to use the AttestUpdate action to assert one or more of the following:
- That builds are reproducible from the source code.
- That they have reviewed the source code and found no evidence of backdoors or exploitable vulnerabilities.
(And then you should let your users decide which of these independent third parties they trust to vet software updates.)
Closing Remarks
The U.S. Government cries and moans a lot about “criminals going dark” and wonders a lot about how to solve the “going dark problem”.If more software developers implement end-to-end encryption in their communications software, then maybe one day they won’t be able to use dragnet surveillance to spy on citizens and they’ll be forced to do actual detective work to solve actual crimes.
Y’know, like their job description actually entails?
Let’s normalize end-to-end encryption. Let’s normalize backdoor-resistant software distribution.
Let’s collectively tell the intelligence community in every sophisticated nation state the one word they don’t hear often enough:
Especially if you’re a furry. Because we improve everything! :3
Questions You Might Have
What About Private Contact Discovery?
That’s one of the major reasons why the thing we’re building isn’t meant to compete with Signal (and it MUST NOT be advertised as such):Signal is a privacy tool, and their servers have no way of identifying who can contact who.
What we’ve built here isn’t a complete privacy solution, it’s only providing end-to-end encryption (and possibly making NSA employees cry at their desk).
Does This Design Work with Federation?
Yes. Each identifier string can be [username] at [hostname].What About Network Metadata?
If you want anonymity, you want to use Tor.Why Are You Using Ed25519 Keys for X3DH?
If you only read the key agreement section of this blog post and the fact that I’m passing around Ed25519 public keys seems weird, you might have missed the identity section of this blog post where I suggested piggybacking on another protocol called Gossamer to handle the distribution of Ed25519 public keys. (Gossamer is also beneficial for backdoor resistance in software update distribution, as described in the subsequent section.)Furthermore, we’re actually using birationally equivalent X25519 keys derived from the Ed25519 keypair for the X3DH step. This is a deviation from what Signal does (using X25519 keys everywhere, then inventing an EdDSA variant to support their usage).
const publicKeyX = await sodium.crypto_sign_ed25519_pk_to_curve25519(foxPublicKey);const secretKeyX = await sodium.crypto_sign_ed25519_sk_to_curve25519(wolfSecretKey);
(Using fox/wolf instead of Alice/Bob, because it’s cuter.)
This design pattern has a few advantages:
- It makes Gossamer integration seamless, which means you can use Ed25519 for identities and still have a deniable X3DH handshake for 1:1 conversations while implementing the rest of the designs proposed.
- This approach to X3DH can be implemented entirely with libsodium functions, without forcing you to write your own cryptography implementations (i.e. for XEdDSA).
The only disadvantages I’m aware of are:
- It deviates from Signal’s core design in a subtle way that means you don’t get to claim the exact same advantages Signal does when it comes to peer review.
- Some cryptographers are distrustful of the use of birationally equivalent X25519 keys from Ed25519 keys (although there isn’t a vulnerability any of them have been able to point me to that doesn’t involve torsion groups–which libsodium’s implementation already avoids).
If these concerns are valid enough to decide against my implementation above, I invite you to talk with cryptographers about your concerns and then propose alternatives.
Has Any of This Been Implemented Already?
You can find implementations for the designs discussed on this blog post below:
- Rawr-X3DH implements X3DH in TypeScript (added 2020-11-23)
I will update this section of the blog post as implementations surface.
#authenticatedEncryption #authenticatedKeyExchange #crypto #cryptography #encryption #endToEndEncryption #libsodium #OnlinePrivacy #privacy #SecurityGuidance #symmetricEncryption
Specifications >> The XEdDSA and VXEdDSA Signature Schemes
This document describes how to create and verify EdDSA-compatible signatures using public key and private key formats initially defined for the X25519 and X448 elliptic curve Diffie-Hellman functions.Signal Messenger
Kreativität
Watch this YT video on on some Invidious instance!
transcript deutsch
gist.github.com/wolfhesse/c935…
ein ding was sie immer tun koennen - also, sie koennen ja nicht wirklich die kreativitaet und innovationsfaehigkeit der mitarbeiter foerdern - da muss man ja schon mal sagen, bitte unterscheiden sie bei allem, was sie tun, zwischen indirekten variablen und direkten variablen.
das ist sehr wichtig.
also, wenn mir jemand sagt, wir machen ein kulturveraenderungsprojekt, dann krieg’ ich weisse haare; jenseits der haare, die ich schon habe, die weiss sind.
weil kultur ist eine indirekte variable, #kultur kann ich nicht erzeugen, kultur ist keine projektarbeit. ich kann nur rahmenbedingungen erzeugen, in denen bestimmte kulturmuster emergieren.
also, wenn sie kreativitaet erzeugen wollen, koennen sie sich fragen: was sind systemische rahmenbedingungen, in denen kreativitaet erscheint? aber sie koennen nicht kreativitaet ‘machen’. sonst kommen wir in diese freundliche methode, dass ich sage: ‘sei kreativ!’
Huch, erschreckt man sich, wie geht das?
das ist mindestens so absurd wie zu sagen, ‘sei spontan, aber bitte jetzt! denk auf keinen fall an einen rosaroten elephanten!’ was machen wir da? wir machen etwas, was nicht wirklich geht.
also bitte, wenn sie ueber kreativitaet reden, reden sie ueber indirekte moeglichkeitsraeume, und nicht ueber das direkte erzeugen. und einer der indirekten moeglichkeitsraeume von kreativitaet ist #diversity. wenn sie unterschiedlichkeit im system erhoehen - ob das kulturell ist, oder stilmaessig, voellig egal. intelligente systeme, die in der lage sind zu akkumulieren, und nicht nur zu assimilieren, die im prozessmuster wechseln koennen, sind immer systeme, die mit internen spannungsverhaeltnissen arbeiten: weil systeme mit internen spannungsverhaeltnissen erzeugen instabile phasen, und systeme mit instabilen phasen erzeugen die moeglichkeit zum uebergang zum neuen muster, und das nennen wir kreativitaet.
also erhoehen sie die spannung im system! schaffen sie unterschiedlichkeit, dann schaffen sie die moeglichkeit zum prozessmusterwechsel. machen sie keine einheitlichkeit! harmonische systeme sind dumme systeme.
in der natur entsteht ordnungsmuster immer aus widerspruch, nicht aus harmonie. das heisst, wenn sie wirklich komplexe ordnungsmuster haben wollen, erhoehen sie bitte die unterschiedlichkeit im system. geben sie querdenkern eine chance, lassen sie die stoerer zu, und - und das ist fast trivial - bauen sie #netzwerke;
weil in dem moment, wo sie ein #netzwerk bauen, schaffen sie eine situation, wo die nichtlinearen rueckkopplungseffekte immer wieder fuer das aufloesen von stabilen zustaenden sorgen. d.h., rueckkopplungsmechanismen und diversitaet sind extrem positiv fuer kreativitaet.
bauen sie netzwerke! sorgen sie dafuer, dass der kollege in china eine unmittelbare wirkung hat auf den kollegen in deutschland. wenn das passiert, und das wirklich funktioniert, dann wird der kollege in china mit seiner unterschiedlichkeit, wenn er denn vernetzt ist, den kollegen in deutschland immer hinreichend aergern und stoeren, dass der eine chance hat, kreativ zu werden; und wenn sie das nicht nur mit einem kollegen und einem kollegen machen, sondern mit einem gigantischen netzwerk, dann, kann ich ihnen sagen, wird die uebersummative intelligenz dieses netzwerkes groesser sein als die summe der einzelintelligenzen: und dann haben wir wirklich was geschafft, und dann reden wir hinterher davon, dass wir viele kreative menschen haben.
suchen sie bitte, vielleicht koennen sie natuerlich suchen nach dem einzelbeispiel des kreativen, so wars frueher: da hat man immer den einzelnen gesucht, der durch irgendeinen biographischen unfall die schmerzen so gut ertraegt, dass er kreativ ist. heute suche ich nicht mehr diesen biographischen unfall; heute versuche ich systeme mir anzuschauen, die diesen biographischen unfall nicht mehr brauchen, weil sie selber ein unfall sind.
und, also, bauen sie systeme, die stoeren!
weil, systeme die nicht stoeren, sind immer stabilitaetsorientierte systeme. sorgen sie dafuer, dass die #komplexitaet und dynamik innerhalb des systemes mindestens so gross ist, wie die komplexitaet und dynamik am markt.
folgen sie einfach Ashby’s Law.
Ashby als systemtheoretiker hat in den fuenfzigerjahren gesagt: wo immer wir ein hochkomplexes dynamisches problemsystem haben, brauchen wir im minimum ein so komplexes dynamisches loesungssytem.
d.h., wenn wir keine gegengleiche komplexitaet haben, sind wir nicht loesungfaehig.
wenn jetzt unsere welt immer komplexer wird, durch vernetzung, kann man sagen: die einzige loesung, die wir haben, ist komplexitaet durch vernetzung; weil dann haben wir die chance. und das gehirn - da sind wir wieder bei meinem ausgangsstatement, das ich nur versucht habe, das gehirn auf management zu uebertragen -
das gehirn macht das vor.
der mensch mit seinem gehirn ist in der lage, vom aequator bis zum nordpol zu ueberleben - das einzige lebewesen, was das kann. warum? weil wir ein komplexes dynamisches system haben, das uns in die lage versetzt, mit komplexen dynamischen systemen zu leben. d.h., nur weil unser gehirn unkalkulierbare dynamiken erzeugt, nur deshalb koennen wir mit unkalkulierbaren dynamiken einigermassen umgehen.
d.h., das gehirn ist eine grosse erfindung der natur im umgang mit unvorhersagbarkeiten. die andere grosse erfindung, die die natur gemacht hat, ist nicht die individuelle intelligenz des gehirns, sondern die kollektive intelligenz des schwarms. das war eine mindestens so grosse intelligenzleistung, d.h. es gibt eigentlich nur zwei durchsetzungsfaehige, wirklich durchsetzungsfaehige mechanismen: das eine sind staatenbildende insekten, die finden sie ueberall auf der welt, sind unglaublich erfolgreich als spezies; und sie haben das individuelle gehirn in der hochentwicklung des menschen. das ist wirklich erfolgreich, weil sie einmal ein dynamisches komplexes system haben, und bei den staatenbildenden insekten auch - nur, beim einen steckt es im individuum, und beim anderen steckt es in der menge der individuen; aber das prinzip ist das gleiche:
hohe #interaktivitaet, hohe rueckkopplungseffekte; und dann koennen sie ordnungsmuster erzeugen.
das ist einfach sehr, sehr effektiv.
und ich versuche in meinen eigenen zusammenhaengen heute, solche systeme immer zu bauen. also, wenn sie sagen wuerden, was machst du eigentlich um erfolgreich zu sein, dann wuerd ich nicht mehr sagen: ‘klug sein’; sondern markt beobachten; das ist schon fast ableitbar. ich versuche immer zu verstehen, was ist da draussen los?
und ansonsten versuche ich, netzwerke zu bauen, und da baue ich eigentlich nur das gehirn nach. in meinen netzwerken gibt es immer drei charaktere von menschen:
es gibt die #Creator, das sind die spinner, die mich immer stoeren, die immer mit neuen ideen kommen. es gibt die #Owner, das sind die wissenseigner. das sind die leute, die etwas im tz beherrschen. und, es gibt die #Broker; das sind die, die leute kennen, die etwas wissen; die vermitteln. und jetzt kann man eigentlich sagen: diese drei personengruppen bilden zusammen ein gehirn.
wenn ich den Creator und den Owner zusammenbringe, bekomme ich ideen. da entsteht naemlich aus wissen und aus instabilitaet ein ideenpool: das ist der cortex.
wenn ich den Owner und den Broker zusammenbringe, habe ich zwei bewerter zusammen. weil, der Broker muss bewerten koennen, ob ein wissen was taugt, und der Owner muss bewerten koennen. hier habe ich das limbische system.
und wenn ich den Broker und den Creator zusammenbringe, dann habe ich erregung. weil, der Broker stoert mich, und der Creator stoert mich. d.h., was bekomme ich dann? eine aufsteigend retikulaer aktivierende formation, die mich immer wieder erregt.
und wenn sie die drei dinge zusammenbringen, Errgegung, Loesungsbildung und Bewertung, dann haben sie ein Gehirn.
was anderes tu ich nicht; ich such mir einfach immer nur diese leute, die diese charakteristiken haben. und glauben sie mir: die unterscheiden sich. sie finden nach kurzer zeit raus, wer ein guter Broker ist. die sind nicht tief in ihren kenntnissen, aber die wissen immer genau, wer’s weiss. und diese Creator, die sind nicht tief in ihren kenntnissen unbedingt, aber die spinnen wie die weltmeister; die koennen unglaublich schnell neue muster erzeugen.
und die Owner sind diese wertvollen leute, die etwas wirklich gut wissen; die aber, wenn sie alleine sind, meistens keine neuen loesungen finden, weil sie die instabilitaet nicht hinbekommen.
d.h., ohne die erregung und ohne die stoerung wird das ganz, ganz schwer.
und so kann man, wenn sie so wollen, intelligente systeme bauen, deren summenintelligenz groesser ist als die intelligenz der beteiligten menschen.
und das ist mein grosses ziel.
#Kreativität #PeterKruse #Kruse
¿Como reaccionan la gente a una complejidad creciente?
5. Intuición: evaluación emocional
El ser humano es capaz de forma fascinante de reducir complejidad a través de crear patrones en su cerebro.
Quiere decir, intuición significa que el cerebro aprendió a través de la experiencia (en situaciones “extremas”), de crear patrones para evaluar una circunstancia.
Problema grande: “estar al día” - si el mundo y/o las circunstancias en que se desarrollo la intuición cambia, el sentimiento intuitivo se siente aun acertado pero esta completamente fuera de foco.
Remedio: Observar antes que nada cuando y como se desarrollo dicha intuición - ¡realmente aun esta “up to date”?
Problema: Si solo dependo de uno solo, ese “emprendedor” puede estar equivocado.
Solución: Intuición colectiva → #Mateada
youtube.com/watch?v=m3QqDOeSah…
#Kruse #ñ #internet #redes #redesSociales #colectivo #cooperación #mitdenken
Kritik-Post zu Bitcoin
Heute ist Freitag, der 3. Januar 2025.Am 3. Januar 2009, vor 16 Jahren wurde der Bitcoin Genesis Block (Block 0) berechnet.
Bitcoin basiert auf den Ideen von Hashcash, also der Idee der nutzlosen Verschwendung von Rechenleistung und substantieller Mengen Energie ("Proof of Work") und einem sehr langsamen und verschwenderischen Protokoll für verteilten Konsens, um damit kryptografisch gesicherte Dinge zu erzeugen, von denen manche Leute glauben, daß sie Wert haben.
Zunächst nahm man an, Bitcoin als Zahlungsmittel verwenden zu können, aber dafür ist es viel zu energieintensiv und zu langsam. Die pseudonyme Struktur von Bitcoin hat es jedoch als Zahlungsmittel für Lösegeldforderungen etabliert, und damit Ransomware möglich gemacht–die Monetarisierung von Sicherheitslücken war vor Bitcoin faktisch unmöglich.
Nach Bitcoin haben sich ein Haufen Epigonen entwickelt, die aber alle weitgehend erfolglos blieben oder deren Kurs mehr oder weniger dem Kurs von Bitcoin folgt. Daran hängend entstand eine "Kryptocoin-Industrie", ein Haufen krimineller Pseudo-"Banken", deren Praktien durchweg keiner Inspektion stand halten.
Um die Technologie zu legitimieren, und weil wir seit circa 20 Jahren eine Kapitalertragskrise haben, war in der IT eine Zeit lang ein Blockchain-Hype. Damals wurde versucht, die Techniken, die Bitcoin ermöglichen, in der IT sinnvoll einzusetzen. Für manche, zum Beispiel den Merkle-Tree, war das aber schon lange der Fall: ZFS, git oder Torrent verwenden Ideen analog dazu. Für andere, zum Beispiel den verteilten Konsens, gibt es andere, schnellere, zuverlässigere und weniger energieintensive Methoden, die ohne Proof-of-Work auskommen–Paxos und Raft sind weit verbreitet. Heute, 16 Jahre nach Bitcoin, gibt es keine einzige Blockchain in einer sinnvollen Anwendung.
Dementsprechend ist Bitcoin heute weitgehend ein Vehikel um die Ahnungslosen um ihr Geld zu bringen und ein Mittel, um kriminelle Unternehmungen zu finanzieren.
Ich finde, Bitcoin ist zu einer art "digitales Gold" geworden: Ein Anlageobjekt, das für Investoren spannend ist, aber das war es auch schon.
Zahlungen im Web hat es sicher nicht revolutioniert.
K9-Mail und FairMail im Vergleich
K9-Mail und FairMail im Vergleich
Weil K9-Mail letztlich aufhört, habe ich mich nach einer Alternativen umgeschaut. Da wird Fair Mail häufig genannt. Das habe ich mir angeschaut, so richtig angetan bin ich aber nicht. Auf dem DesktoMartin Ueding
Ich bin vor Jahren von K9 zu fairmail gewechselt. Ehrlicherweise weiß ich gar nicht mehr warum.
Aber FairMail ist für mich einfach super. Umfangreich, alle Features die ich brauche und auch manche, die ich nicht (oft) verwende.
Ein Nischenfeature ist z.b. die Unterstützung von S/Mime.
AMD Radeon RX 9070 XT Pricing Leak: More Affordable Than RTX 5070?
AMD Radeon RX 9070 XT Pricing Leak: More Affordable Than RTX 5070?
As we reported yesterday, the Radeon RX 9070 XT appears to be all set to disrupt the mid-range gaming GPU segment, offering performance that looks truly enticing, at least if the leaked synthetic benchmarks are anything to go by.TechPowerUp
Also sourced from Chiphell, the Radeon RX 9070 XT is expected to command a price tag between $479 for AMD's reference card and roughly $549 for an AIB unit, varying based on which exact product one opts for.
This sounds reasonable IMO. After all, there is still room for a cheaper 9060 / 9050 series.
Meta beendet laut Medien auch internes Diversitätsprogramm
Meta beendet laut Medien auch internes Diversitätsprogramm
Der Facobook-Konzern Meta beendet laut Medienberichten sein Programm für mehr Chancengleichheit und Diversität. Grund soll der "Wandel der politischen Landschaft" sein. US-Präsident Biden kritisiert unterdessen einen andere Entscheidung.tagesschau.de
Die aktuelle Lage macht wieder mal deutlich, wie viel Einfluss die amerikanischen Tech Unternehmen haben.
Soziale Medien, Betriebssysteme, Suchmaschinen etc sind fast alle US-basiert.
Wär Zeit für alternative Dienste, irgendwas dezentrales z.B. 😀
Das Hirn ist schön. Das Hirn ist lieb. Das Hirn ist gut. Und Beton ist das auch.
Unendlich langsam komme ich voran. Es ist zum Heulen. Das Hirn widersetzt sich. Obschon, es ist ein gutes Hirn. Das Hirn ist lieb. Das Hirn ist schön. Das Hirn ist gut. So ähnlich stand es vor zwanzig Jahren an einer Brücke über den Rhein zwischen Mannheim und Ludwigshafen geschrieben. Ich kam von Mannheim, vermutlich per Rad und flanierte am Beton, worauf gesprayt war in großen Lettern: Beton ist schön, Beton ist lieb, Beton ist gut. Halbmeter hohe Buchstaben über zwanzig dreißig Meter verteilt, so will es die Erinnerung. Und ist das etwa nichts? Diese Erinnerung, so weit weg an Jahren, so unbedeutend, so nicht erinnerungswürdig eigentlich und doch hat sie sich gehalten.
Vielleicht bilde ich mir das alles nur ein?
Am Morgen fummelte ich fahrig auf Webseiten, installierte für die Radelgalerie, die ich dieses Jahr wieder in Betrieb nehmen möchte, eine Classicpress-Seite und versuchte eine andere eher wenig wichtige meiner Seiten in Classicpress zu verwandeln, scheiterte mit dem Verwandeln (weißer Bildschirm des Todes), hatte Erfolg mit der Radelgalerie und der Tag verging im Forschen darum warum das Verwandeln nicht geklappt hatte und im Versuch, die Radelgalerie schön einzurichten. Dort fehlt es nun nur noch an Inhalten. Nuja und dabei ist das Hirn gefragt. Wann waren nochmal meine spärlichen Aktionen mit der Radelgalerie? 2019? Oder früher? Es war Mai. Ich muss alle Maimonatsarchive im Bildarchiv absuchen und tatsächlich, werde fündig. Die Radelgalerie beim Straßentheaterspektakel in Zweibrücken. Bin unzufrieden mit den Bildern, hey und war ich nicht 21 in Saarbrücken mit der Galerie? September. Parkingday. Oder war das 2022. Covid, Du verflixter kleiner Hirnvernebler, Du elender Zeitverdrullerer! Vor Dir war alles so schön gefügt und chronologisch, aber seit Dir nur noch Matsch, Schmier, Verschiebung, Nebel …
Herrjeh.
So trete ich auf der Stelle und etwas lenkt mich ab und der Abend naht und ich verliere die Lust und eigentlich hätte ich sollen dranbleiben am Schreiben: Gestern liefs doch so gut mit der Geschichte „Wo Hotel“ – anderthalb Stunden und die Story war fertig, dann nur noch bissel Korrektorat – sowas könnte ich öfter gebrauchen. Immer. Jeden Tag. Verflixt! Ich rotiere von Idee zu Idee, Gedanke zu Gedanke, kaum die Muse etwas zu Ende zu führen. Daran muss ich arbeiten. Am Es-zu-Ende-bringen.
Dieses Jahr.
Ich hab kaum noch Zeit, ahne ich. Ne, fürchte ich.
Was ist denn der Unterschied zwischen Ahnen und Fürchten und sollte man darüber eine Abhandlung schreiben? Wer, wenn nicht ich? Wozu?
Heute: Mit dem Radel zum Reparaturcafé geradelt. Kaffee getrunken, Kuchen gegessen, geplaudert, zum Aldi gegenüber und wieder hoch mit den letzten KWH im Akku. Dabei einen Warmhandhack ausprobiert mit zerschnittener Isomatte über den Lenkerenden, die eine Protektion für die Hände bietet. Das war fein. Ich probierte eine Hand mit und eine ohne Protektions-Isomatte und siehe da, die mit, die war wärmer oder nicht so kalt und wenn es regnet, bringt die Isomattenprotektion vermutlich richtig viel, weil es dauert, bis die Handschuhe durchnässt sind. Ich Fuchs.
Eigentlich hatte ich im Hinterkopf, morgen nach Mainz zu radeln zu Freund QQlka, um ihm zum Geburtstag zu gratulieren, bisschen schwätzen und sonntags wieder heim. Bloß: Ich krieg verflixt den Hintern nicht hoch. Dauert immer bis Mittag, bis ich warmlaufe, um mich im Irrgarten der Zutuns zu verirren. Es wäre sicher kein Fehler, mal raus, das Haus verlassen, klare Linie finden, Schritt für Schritt voran, statt auf der Stelle zu tippeln und hier dies und da das und nichts wird fertig.
So auch die Idee, nächste Woche ein erstes Mit-dem-Rad-zur-Liebsten zu wagen. Die Tour dauert drei Tage, also zwei Zeltübernachtungen im Elsass irgendwo. Die Strecke ist fast ausschließlich auf Radwegen und ich kenne sie in- und auswendig. Das Wetter soll ja schön werden, nachts kalt, trocken, nicht weniger als minus vier. Das wäre eventuell noch zeltbar, jaja und dann hätte ich, vom Zwang der Radreise diktiert, auch eine Struktur. Denk mal dran, liebes Jetzt-Ich, der du dies schreibst, wenn du dich morgen in ein ungeheuerliches Morgen-Ich verwandelt siehst und nicht mehr weißt noch ein noch aus ob all der Möglichkeiten, die auf dich einprasseln. Jetzt, jetzt und jetzt … also im morgigen Jetzt, nicht im jetztigen Jetzt.
War eigentlich als Privateintrag gedacht. Aber hopp, raus damit.
Supporten kannst Du mich per Paypal: paypal.me/JRinck133
Oder im Shop was kaufen: shop.irgendlink.de/
Oder woanders abgefahrene Hemden drucken lassen: seedshirt.de/shop/irgendlink
Maul- und Klauenseuche – Özdemir ruft zentralen Krisenstab ein
Ausbruch der Maul- und Klauenseuche in Brandenburg: Tiergesundheit in in ganz Deutschland Gefahr
Die Maul- und Klauenseuche ist in Deutschland ausgebrochen. Eine Herde Wasserbüffel musste in Brandenburg getötet werden. Das könnte Auswirkungen auf ganz Deutschland haben.Tobias Betz (BR24)
Bis zu 1000 US-Dollar im Monat: OpenAI überdenkt Abo-Modelle für ChatGPT
Bis zu 1000 US-Dollar im Monat: OpenAI überdenkt Abo-Modelle für ChatGPT
OpenAI prüft flexiblere Preismodelle – abhängig von der Nutzung. Sam Altman meint, 1000 US-Dollar für einen Monat seien möglich.Eva-Maria Weiß (heise online)
Das würde ich so ohne weiteres nicht unbedingt glauben:
- Wie oft macht openAI Verlust mit diesem Plan? Bei 100%, 10%, 1% der Nutzer?
- Was heißt "Verlust" überhaupt in diesem Kontext? Haben die User einen Stromverbrauch, der die 200$ übersteigt? Sind da die Kosten für Training und Entwicklung enthalten?
Von daher halte ich das eher für Marketing und den Versuch, gerade die Power User an teure Tarife zu gewöhnen. Gut möglich, dass da bald noch höhere Preise ausgerufen werden, wenn die Leute das zahlen.
Verwirrung um kaputte Altkleider: Doch in den Restmüll
Die EU hat Ernst gemacht: Seit Januar dürfen Textilien nicht mehr im Restmüll landen – eigentlich. In Deutschland sieht die Situation anders aus, sodass sich unser Land vorerst der EU-Vorgabe widersetzt: Verschlissene und schmutzige Kleidung kommt weiter in den Restmüll.Mit der neuen Richtlinie will die EU das Textilrecycling ankurbeln und Millionen Tonnen Kleidung und Stoffe vor der Müllverbrennung bewahren. Sie schreibt vor, dass alle Textilien separat entsorgt werden müssen. Bisher landeten EU-weit nur rund 22 Prozent der Alttextilien in speziellen Sammelsystemen. Der Rest wurde verbrannt oder deponiert.
Deutschland gehört in Sachen Altkleider-Sammlung mit einer Quote von 50 bis 65 Prozent zu den Vorreitern. Hier übernehmen gemeinnützige Organisationen wie das Deutsche Rote Kreuz oder die AWO diese Aufgabe. In Lettland liegt die Quote laut Europäischer Umweltagentur bei knapp fünf Prozent, in Spanien bei rund zwölf Prozent. Die neue Regelung soll hier mehr Bewusstsein schaffen.
Viele Verbraucher in Deutschland fragen sich nun, ob wirklich alles in die Altkleidersammlung soll – auch stark beschädigte oder verschmutzte Textilien. Die Antwort: Nein.
"Stark verdreckte oder unbrauchbare Kleidungsstücke sollten weiterhin in den Restmüll", heißt es von der Verbraucherzentrale, dem Verband der kommunalen Unternehmen (VKU) sowie etlichen Kommunen. Brauchbare Kleidung gehört wie gehabt in die Altkleidersammlung.
Verschlissene Stoffe würden die Qualität der Sammlung beeinträchtigen. Eine Vermischung könnte das System überfordern. Die Sortierung von brauchbaren und unbrauchbaren Textilien ist teuer und aufwendig, vor allem, da vieles von Hand gemacht werden muss.
Verwirrung um kaputte Altkleider: Restmüll oder nicht?
Neue EU-Richtlinie: Seit Januar dürfen Textilien eigentlich nicht mehr in den Restmüll. Damit will die EU das Textilrecycling ankurbeln. Doch in Deutschland ist die Wiederverwertungsquote bereits so hoch, dass sich trotz der Richtlinie nichts ändert.Til Antonie Wiesbeck (BR24)
Abkehr von Klimaziel: Scharfe Kritik an (bayrischer) Staatsregierung
Abkehr von Klimaziel: Scharfe Kritik an Staatsregierung
"Wahnsinn", "unverantwortlich", "fatal": Nach dem BR-Bericht über die Abkehr der Staatsregierung vom eigenen Klimaziel gibt es viel Kritik aus der Opposition und von Umweltverbänden. Differenzierter reagiert die bayerische Wirtschaft.Petr Jerabek (BR24)
cron mag das.
It would be better if the login flow said something like
For security reasons, we ask you to set a new password, please use the "password forgotten" function to gain access again.
instead of me being puzzled why my password doesn't work.
I once had to reset my password as the new one got truncated without telling me.
Yes. It was deemed too long.
It was for an company that got plenty of my personal data
cron mag das.
I've never really understood why most systems are set up to reject a password reset if it's the same password. Is there a security issue there that I'm not picking up on?
It seems like they should just let you reset your password anyway if you've reached that screen (usually using some kind of authorisation, like using a link with a token in it that gets emailed to you or something).
Renault zeigt Interieur des neuen Twingo E-Tech Electric
Renault zeigt Interieur des neuen Elektro-Twingo - ecomento.de
Auf der Motor Show in Brüssel wirft Renault einen Blick in den Innenraum des 2026 auf den Markt kommenden neuen elektrischen Twingo.ecomento.de (ecomento)
Im Artikel war keine, üblich wären 40-50 kWh und damit ~300 km.
Als Vergleich, der e-C3 liegt bei 44 kWh und kommt damit 324 km laut WLTP.
Der Kofferraum fühlt sich auf den Bildern arg klein an, wenn der so winzig wie bei einem E-Up ist, wird das eng beim Einkaufen ;)
Aber was Reichweite betrifft, sehe ich kein Problem. Locker 200+ km und dann mit CCS nachladen, falls man doch mal weiter fährt. Und ein Twingo ist eh kein Urlaubsauto für die Strecke Hamburg-Sizilien.
Might as well get a laptop???
CES 2025: The Acer Nitro Blaze 11 Gaming Handheld Is an Absolute Unit
You're gonna need a bigger bag.Michelle Ehrhardt (Lifehacker)
The iPad probably weights less than half what this thing does, and probably takes up a lot less space.
Also it's probably faster and almost certainly gets better battery life.
iPads have ridiculously powerful cpus and gpus
If an iPad ran steamos and supported steam controller in some kind of wacky timeline it would clean up all the competition. This thing is like 400g for 13 inch oled m4 beast battery all day. The numbers are pure insanity
Thats both true and not really relevant, considering the iPad's game library.
Edit: It would be really interesting to see an Apple-made portable game console, featuring it's M-Series chips.
cron mag das.
this is basically the oversized razer kishi pro with an ipad mini.
ive got that rn and it's pretty amazing as a steam link device.
steamos really needs to fix their steam link code, it's a mess.
Evan Prodromou
Als Antwort auf Social Web Foundation • • •mray
Als Antwort auf Social Web Foundation • • •