<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>MFA &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/mfa/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Sat, 11 Apr 2026 06:53:47 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>MFA &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Some minor bugs in Proton's new Authenticator app]]></title>
		<link>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/</link>
					<comments>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 31 Aug 2025 11:34:55 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Proton]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=62350</guid>

					<description><![CDATA[I maintain a a test-suite for TOTP codes. It contains a bunch of codes which adhere to the specification, some of which stretch it to breaking point, and some that are completely invalid.  These codes are a good starting point for checking whether a 2FA / MFA app works correctly.  Proton have release a swish new authenticator app for Android, iOS, Mac, Linux and Windows. Sadly, their open source…]]></description>
										<content:encoded><![CDATA[<p>I maintain a <a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/">a test-suite for TOTP codes</a>. It contains a bunch of codes which adhere to the specification, some of which stretch it to breaking point, and some that are completely invalid.  These codes are a good starting point for checking whether a 2FA / MFA app works correctly.</p>

<p>Proton have release a swish <a href="https://proton.me/authenticator">new authenticator app</a> for Android, iOS, Mac, Linux and Windows. Sadly, their <a href="https://github.com/protonpass/android-pass">open source repository</a> doesn't allow for bug reports so I'm blogging in public instead.</p>

<p>The good news is, the majority of tests pass. It accepts a wide range of acceptable codes and refuses to store most broken ones. There are a few niggles though.  None of these are severe security issues, but they probably ought to be fixed.</p>

<h2 id="very-long-codes"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#very-long-codes">Very long codes</a></h2>

<p>The maximum number of digits which can be generated by the standard TOTP algorithm is 10.  Proton happily scans codes containing 1 - 9 digits, but complains about 10 digit codes.  So this fails:</p>

<p><code>otpauth://totp/issuer%3Aaccount%20name?secret=QWERTYUIOP&amp;digits=10&amp;issuer=issuer&amp;algorithm=SHA1&amp;period=30</code></p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/10digit.webp" alt="QR code for a 10 digit TOTP." width="360" height="360" class="aligncenter size-full wp-image-62370">

<p>The TOTP RFC says:</p>

<blockquote><p>Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">1.2. Background</a></p></blockquote>

<p>But doesn't say how far to truncate.</p>

<p>There's nothing I can see in the spec that <em>prevents</em> an implementer using all 10.</p>

<p><strong>Risk:</strong> The user may not be able to store a valid code.</p>

<p><strong>Recommendation:</strong> Allow 10 digit codes.</p>

<h2 id="invalid-secrets"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#invalid-secrets">Invalid Secrets</a></h2>

<p>Here we get to yet another <a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/">deficiency in the TOTP specification</a>.  How is a secret defined?</p>

<p>Google says the secret is:</p>

<blockquote><p>an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted.</p></blockquote>

<p>Whereas Apple says it is:</p>

<blockquote><p>An arbitrary key value encoded in Base32. Secrets should be at least 160 bits.</p></blockquote>

<p>Either way, <a href="https://www.rfc-editor.org/rfc/rfc3548#section-5">the Base32 alphabet</a> contains only uppercase letters and a few numbers.  What happens if we give it a secret like <code>QWERT!£$%^)*(YUIOP</code>?</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/invaid-secret.webp" alt="QR code for an invalid secret." width="360" height="360" class="aligncenter size-full wp-image-62371">

<p>Proton Authenticator just accepts it. It stores the full secret but I'm not sure how it generates the code based on it.</p>

<p><strong>Risk:</strong> The code may be generated incorrectly.</p>

<p><strong>Recommendation:</strong> Warn the user that the secret may be invalid and that a correct 2FA code cannot be guaranteed.</p>

<h2 id="issuer-mismatch"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#issuer-mismatch">Issuer Mismatch</a></h2>

<p>In this example, the first issuer is example.com but the second issuer is microsoft.com</p>

<p><code>otpauth://totp/example.com%3Aaccount%20name?secret=QWERTYUIOP&amp;digits=6&amp;issuer=microsoft.com&amp;algorithm=SHA1&amp;period=30</code></p>

<p>What should the TOTP reader do with this? Proton chooses microsoft.com.</p>

<p>This is something which, again, is inconsistent between major providers.</p>

<p>Google says this parameter is:</p>

<blockquote><p><strong>Strongly Recommended</strong> The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal.</p></blockquote>

<p>Apple merely says:</p>

<blockquote><p>The domain of the site or app. The password manager uses this field to suggest credentials when setting up a new code generator.</p></blockquote>

<p>Yubico equivocates with</p>

<blockquote><p>The issuer parameter is recommended, but it can be absent. Also, the issuer parameter and issuer string in label should be equal.</p></blockquote>

<p><strong>Risk:</strong> The code may be displayed with the wrong issuer.</p>

<p><strong>Recommendation:</strong> Warn the user that there are multiple issuers. Let them choose which one is correct.</p>

<h2 id="dealing-with-defaults"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#dealing-with-defaults">Dealing With Defaults</a></h2>

<p>What should a TOTP app do if there is missing information? Proton does the following:</p>

<ul>
<li>If the code has no number set for digits, it defaults to 6</li>
<li>If the code has no time set for period, it defaults to 30</li>
<li>If the code has no algorithm, it defaults to SHA1</li>
</ul>

<p><strong>Risk:</strong> Low. The user normally has to confirm with the issuer that the the TOTP code has been correctly stored.</p>

<p><strong>Recommendation:</strong> Let the user know that the code has missing data and may not be correct.</p>

<h2 id="odd-labels"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#odd-labels">Odd Labels</a></h2>

<p>The label allows you to have multiple codes for the same service. For example <code>Big Bank:Personal Account</code> and <code>Big Bank:Family Savings</code>.  The Google spec is slightly confusing:</p>

<blockquote><p>The issuer prefix and account name should be separated by a literal or url-encoded colon, and optional spaces may precede the account name. Neither issuer nor account name may themselves contain a colon.</p></blockquote>

<p>What happens if there are spaces before the account name?</p>

<p><code>otpauth://totp/Spaces:%20%20%20%20%20%20%20%20%20%20%20%20test%40example.com?secret=QWERTYUIOP&amp;digits=6&amp;issuer=&amp;algorithm=SHA1&amp;period=30</code>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/08/spaces.webp" alt="QR code for a TOTP." width="400" height="400" class="aligncenter size-full wp-image-62374"></p>

<p>Proton strips the spaces (probably wise) but also removes the issuer.</p>

<p><strong>Risk:</strong> The user will not know which account the code is for.</p>

<p><strong>Recommendation:</strong> Keep the issuer.</p>

<h2 id="timeline"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#timeline">Timeline</a></h2>

<p>These aren't particularly high severity bugs, nevertheless I like to give organisations a bit of time to respond.</p>

<ul>
<li>2025-07-31 - Discovered.</li>
<li>2025-08-01 - Disclosed <a href="https://bsky.app/profile/proton.me/post/3lvbnajumh22e">via a web form</a>.</li>
<li>2025-08-31 - Automatically published.</li>
</ul>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/#next-steps">Next Steps</a></h2>

<ul>
<li>If you're a user, <a href="https://codeberg.org/edent/TOTP_Test_Suite">please contribute tests</a> or give feedback.</li>
<li>If you're a developer, please check your app conforms to the specification.</li>
<li>If you're from a security company - wanna help me write up a proper RFC so this doesn't cause issues in the future?</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=62350&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/08/some-minor-bugs-in-protons-new-authenticator-app/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[That's Not How A SIM Swap Attack Works]]></title>
		<link>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/</link>
					<comments>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Thu, 17 Apr 2025 11:34:54 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[sim]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=59603</guid>

					<description><![CDATA[There&#039;s a disturbing article in The Guardian about a person who was on the receiving end of a successful cybersecurity attack.  EE texted to say they had processed my sim activation request, and the new sim would be active in 24 hours. I was told to contact them if I hadn’t requested this. I hadn’t, so I did so immediately. Twenty-four hours later, my mobile stopped working and money was wit…]]></description>
										<content:encoded><![CDATA[<p>There's <a href="https://www.theguardian.com/money/2025/apr/15/ee-was-unapologetic-after-i-tried-to-stop-a-sim-swap">a disturbing article in The Guardian</a> about a person who was on the receiving end of a successful cybersecurity attack.</p>

<blockquote><p>EE texted to say they had processed my sim activation request, and the new sim would be active in 24 hours. I was told to contact them if I hadn’t requested this. I hadn’t, so I did so immediately. Twenty-four hours later, my mobile stopped working and money was withdrawn from my bank account.
</p><p><strong>With their alien sim, the ­fraudster infiltrated my handset and stole details for every account I had.</strong> Passwords and logins had been changed for my finance, retail and some social media accounts. </p></blockquote>

<p>(Emphasis added.)</p>

<p>I realise it is in the consumer rights section of the newspaper, not the technology section, and I dare-say some editorialising has gone on, but that's <em>nonsense</em>.</p>

<p>Here's how a SIM swap works.</p>

<ol>
<li>Attacker convinces your phone company to reassign your telephone number to a new SIM.</li>
<li>Attacker goes to a website where you have an account, and initiates a password reset.</li>
<li>Website sends a verification code to your phone number, which is now in the hands of the attacker.</li>
<li>Attacker supplies verification code and gets into your account.</li>
</ol>

<p>Do you notice the missing step there?</p>

<p>At no point does the attacker "infiltrate" your handset. Your handset is still in your possession. The SIM is dead, but that doesn't give the attacker access to the phone itself. There is simply <strong>no way</strong> for someone to put a new SIM into their phone and automatically get access to your device.</p>

<p>Try it now. Take your SIM out of your phone and put it into a new one. Do all of your apps suddenly appear? Are your usernames and passwords visible to you? No.</p>

<p>There are ways to transfer your data from an <a href="https://support.apple.com/en-gb/HT210216">iPhone</a> or <a href="https://support.google.com/android/answer/13761358?hl=en">Android</a> - but they require a lot more work than swapping a SIM.</p>

<p>So how did the attacker know which websites to target and what username to use?</p>

<h2 id="what-probably-happened"><a href="https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#what-probably-happened">What (Probably) Happened</a></h2>

<p>Let's assume the person in the article didn't have malware on their device and hadn't handed over all their details to a cold caller.</p>

<p>The most obvious answer is that the attacker <em>already</em> knew the victim's email address. Maybe the victim gave out their phone number and email to some dodgy site, or they're listed on their contact page, or something like that.</p>

<p>The attacker now has two routes.</p>

<p>First is "hit and hope". They try the email address on hundreds of popular sites' password reset page until they get a match. That's time-consuming given the vast volume of websites.</p>

<p>Second is targetting your email. If the attacker can get into your email, they can see which sites you use, who your bank is, and where you shop.  They can target those specific sites, perform a password reset, and get your details.</p>

<p>I strongly suspect it is the latter which has happened. The swapped SIM was used to reset the victim's email password. Once in the email, all the accounts were easily found. At no point was the handset broken into.</p>

<h2 id="what-can-i-do-to-protect-myself"><a href="https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/#what-can-i-do-to-protect-myself">What can I do to protect myself?</a></h2>

<p>It is important to realise that <a href="https://shkspr.mobi/blog/2024/03/theres-nothing-you-can-do-to-prevent-a-sim-swap-attack/">there's nothing you can do to prevent a SIM-swap attack</a>! Your phone company is probably incompetent and their staff can easily be bribed. You do not control your phone number. If you get hit by a SIM swap, it almost certainly isn't your fault.</p>

<p>So here are some practical steps anyone can take to reduce the likelihood and effectiveness of this class of attack:</p>

<ul>
<li>Remember that <a href="https://shkspr.mobi/blog/2020/03/its-ok-to-lie-to-wifi-providers/">it's OK to lie to WiFi providers</a> and other people who ask for your details. You don't need to give someone your email for a receipt. You don't need to hand over your real phone number on a survey. This is the most important thing you can do.</li>
<li>Try to hack yourself. How easy would it be for an attacker who had stolen your phone number to also steal your email address? Open up a private browser window and try to reset your email password. What do you notice? How could you secure yourself better?</li>
<li>Don't use SMS for two-factor authentication. If you are given a choice of 2FA methods, use a dedicated app. If the only option you're given is SMS - contact the company to complain, or leave for a different provider.</li>
<li>Don't rely on a <a href="https://bsky.app/profile/scientits.bsky.social/post/3lmz2zaxkf22k">setting a PIN for your SIM</a>. The PIN only protects the physical SIM from being moved to a new device; it does nothing to stop your number being ported to a new SIM.</li>
<li>Finally, realise that professional criminals only need to be lucky once but you need to be lucky all the time.</li>
</ul>

<p>Stay safe out there.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=59603&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/04/thats-not-how-a-sim-swap-attack-works/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[FobCam '25 - All my MFA tokens on one page]]></title>
		<link>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/</link>
					<comments>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 11 Apr 2025 11:34:34 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Satire (Probably)]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=59334</guid>

					<description><![CDATA[Some ideas are timeless. Back in 2004, an anonymous genius set up &#34;FobCam&#34;. Tired of having to carry around an RSA SecurID token everywhere, our hero simply left the fob at home with an early webcam pointing at it. And then left the page open for all to see.    Security expert Bruce Schneier approved of this trade-off between security and usability - saying what we&#039;re all thinking:  Here’s a guy w…]]></description>
										<content:encoded><![CDATA[<p>Some ideas are timeless. Back in 2004, an anonymous genius set up "<a href="https://web.archive.org/web/20060215092922/http://fob.webhop.net/">FobCam</a>". Tired of having to carry around an RSA SecurID token everywhere, our hero simply left the fob at home with an early webcam pointing at it. And then left the page open for all to see.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2025/04/FobCam-fs8.png" alt="Website with a grainy webcam photo of a SecurID fob." width="512" class="aligncenter size-full wp-image-59341">

<p>Security expert Bruce Schneier approved<sup id="fnref:🫠"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🫠" class="footnote-ref" title="🫠" role="doc-noteref">0</a></sup> of this trade-off between security and usability - saying what we're all thinking:</p>

<blockquote><p>Here’s a guy who has a webcam pointing at his SecurID token, so he doesn’t have to remember to carry it around. Here’s the strange thing: unless you know who the webpage belongs to, it’s still good security.
<a href="https://www.schneier.com/crypto-gram/archives/2004/0815.html#:~:text=webcam">Crypto-Gram - August 15, 2004</a></p></blockquote>

<p>Nowadays, we have to carry dozens of these tokens with us. Although, unlike the poor schmucks of 2004, we have an app for that. But I don't always have access to my phone. Sometimes I'm in a secure location where I can't access my electronics. Sometimes my phone gets stolen, and I need to log into Facebook to whinge about it. Sometimes I just can't be bothered to remember which fingerprint unlocks my phone<sup id="fnref:🖕"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🖕" class="footnote-ref" title="🖕" role="doc-noteref">1</a></sup>.</p>

<p>Using the <a href="https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to-generate-totp-codes-in-javascript-without-3rd-party-libraries/">Web Crypto API, it is easy to Generate TOTP Codes in JavaScript directly in the browser</a>.  So here are all my important MFA tokens. If I ever need to log in somewhere, I can just visit this page and grab the code I need<sup id="fnref:🙃"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🙃" class="footnote-ref" title="🙃" role="doc-noteref">2</a></sup>.</p>

<h2 id="all-my-important-codes"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#all-my-important-codes">All My Important Codes</a></h2>

<table>
<tbody><tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/github.svg" width="100" title="Github"></td><td id="otp0"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/bitwarden.svg" width="100" title="BitWarden"></td><td id="otp1"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/apple.svg" width="100" title="Apple"></td><td id="otp2"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/ebay.svg" width="100" title="ebay"></td><td id="otp3"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/amazon.svg" width="100" title="Amazon"></td><td id="otp4"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/npm.svg" width="100" title="NPM"></td><td id="otp5"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/paypal.svg" width="100" title="PayPal"></td><td id="otp6"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/facebook.svg" width="100" title="Facebook"></td><td id="otp7"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/zoom.svg" width="100" title="Zoom"></td><td id="otp8"></td></tr>
<tr><td><img src="https://edent.github.io/SuperTinyIcons/images/svg/linkedin.svg" width="100" title="LinkedIn"></td><td id="otp9"></td></tr>
</tbody></table>

<h2 id="what-the-actual-fuck"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#what-the-actual-fuck">What The <em>Actual</em> Fuck?</a></h2>

<p>A 2007 paper called <a href="https://cups.cs.cmu.edu/soups/2007/proceedings/p64_bauer.pdf">Lessons learned from the deployment of a smartphone-based access-control system</a> looked at whether fobs met the needs of their users:</p>

<blockquote><p>However, we observed that end users tend to be most concerned about how convenient [fobs] are to use. There are many examples of end users of widely used access-control technologies readily sacrificing security for convenience. For example, it is well known that users often write their passwords on post-it notes and stick them to their computer monitors. Other users are more inventive: a good example is the user who pointed a webcam at his fob and published the image online so he would not have to carry the fob around.</p></blockquote>

<p>As for Schneier's suggestion that anonymity added protection, a contemporary report noted that <a href="https://www.schneier.com/crypto-gram/archives/2004/0915.html#:~:text=Fobcam">the owner of the FobCam site was trivial to identify</a><sup id="fnref:dox"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:dox" class="footnote-ref" title="The neologism &quot;doxing&quot; hadn't yet been invented." role="doc-noteref">3</a></sup>.</p>

<p>Every security system involves trade-offs. I have a password manager, but with over a thousand passwords in it, the process of navigating and maintaining becomes a burden. <a href="https://shkspr.mobi/blog/2020/08/i-have-4-2fa-coverage/">The number of 2FA tokens I have is also rising</a>. All of these security factors need backing up. Those back-ups need testing<sup id="fnref:back"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:back" class="footnote-ref" title="As was written by the prophets: &quot;Only wimps use tape backup: real men just upload their important stuff on ftp, and let the rest of the world mirror it&quot;" role="doc-noteref">4</a></sup>. It is an endless cycle of drudgery.</p>

<p>What's a rational user supposed to do<sup id="fnref:rat"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:rat" class="footnote-ref" title="I in no way imply that I am rational." role="doc-noteref">5</a></sup>? I suppose I could buy a couple of hardware keys, keep one in an off-site location, but somehow keep both in sync, and hope that a firmware-update doesn't brick them.</p>

<p>Should I just upload all of my passwords, tokens, secrets, recovery codes, passkeys, and biometrics<sup id="fnref:bro"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:bro" class="footnote-ref" title="Just one more factor, that'll fix security, just gotta add one more factor bro." role="doc-noteref">6</a></sup> into the cloud?</p>

<p>The cloud is just someone else's computer. This website is <em>my</em> computer. So I'm going to upload all my factors here. What's the worst that could happen<sup id="fnref:🤯"><a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fn:🤯" class="footnote-ref" title="This is left as an exercise for the reader." role="doc-noteref">7</a></sup>.</p>

<script>async function generateTOTP( 
    base32Secret = "QWERTY", 
    interval = 30, 
    length = 6, 
    algorithm = "SHA-1" ) {
    
    //  Decode the secret
    //  The Base32 Alphabet is specified at https://datatracker.ietf.org/doc/html/rfc4648#section-6
    const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    let bits = "";
    
    //  Some secrets are padded with the `=` character. Remove padding.
    //  https://datatracker.ietf.org/doc/html/rfc3548#section-2.2
    base32Secret = base32Secret.replace( /=+$/, "" )

    //  Loop through the trimmed secret
    for ( let char of base32Secret ) {
        //  Ensure the secret's characters are upper case
        const value = alphabet.indexOf( char.toUpperCase() );

        //  If the character doesn't appear in the alphabet.
        if (value === -1) throw new Error( "Invalid Base32 character" );
        
        //  Binary representation of where the character is in the alphabet
        bits += value.toString( 2 ).padStart( 5, "0" );
    }

    //  Turn the bits into bytes
    let bytes = [];
    //  Loop through the bits, eight at a time
    for ( let i = 0; i < bits.length; i += 8 ) {
        if ( bits.length - i >= 8 ) {
                bytes.push( parseInt( bits.substring( i, i + 8 ), 2 ) );
        }
    }

    //  Turn those bytes into an array
    const decodedSecret = new Uint8Array( bytes );
    
    //  Number of seconds since Unix Epoch
    const timeStamp = Date.now() / 1000; 

    //  Number of intervals since Unix Epoch
    //  https://datatracker.ietf.org/doc/html/rfc6238#section-4.2
    const timeCounter = Math.floor( timeStamp / interval );

    //  Number of intervals in hexadecimal
    const timeHex = timeCounter.toString( 16 );

    //  Left-Pad with 0
    const paddedHex = timeHex.padStart( 16, "0" );

    //  Set up a buffer to hold the data
    const timeBuffer = new ArrayBuffer( 8 );
    const timeView   = new DataView( timeBuffer );
    
    //  Take the hex string, split it into 2-character chunks 
    const timeBytes = paddedHex.match( /.{1,2}/g ).map(
        //  Convert to bytes
        byte => parseInt( byte, 16 )
    );

    //  Write each byte into timeBuffer.
    for ( let i = 0; i < 8; i++ ) {
         timeView.setUint8(i, timeBytes[i]);
    }
    
    //  Use Web Crypto API to generate the HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
    const key = await crypto.subtle.importKey(
        "raw",
        decodedSecret,
        { 
            name: "HMAC", 
            hash: algorithm 
        },
        false,
        ["sign"]
    );

    //  Sign the timeBuffer with the generated HMAC key
    //  https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign
    const signature = await crypto.subtle.sign( "HMAC", key, timeBuffer );
    
    //  Get HMAC as bytes
    const hmac = new Uint8Array( signature );

    //  https://datatracker.ietf.org/doc/html/rfc4226#section-5.4
    //  Use the last byte to generate the offset
    const offset = hmac[ hmac.length - 1 ] & 0x0f;

    //  Bit Twiddling operations
    const binaryCode = 
        ( ( hmac[ offset     ] & 0x7f ) << 24 ) |
        ( ( hmac[ offset + 1 ] & 0xff ) << 16 ) |
        ( ( hmac[ offset + 2 ] & 0xff ) <<  8 ) |
        ( ( hmac[ offset + 3 ] & 0xff ) );

    //  Turn the binary code into a decimal string
    const stringOTP = binaryCode.toString();

    //  Count backwards from the last character for the length of the code
    let otp = stringOTP.slice( -length)

    //  Pad with 0 to full length
    otp = otp.padStart( length, "0" );

    //  All done!
    return otp;
}
//  Placeholder for OTPs
var otps = [];

//  Do you really think these are my genuine codes? At least one of them is. But which?
var otpData = 
    [
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "IPT5TRO7VFK66M6SHUJ7XZNM2U6IZZ4L"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "EXGKOX26KMDSTL6KM3BYMPXXDDKNQEYM"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "UGVGXRQFHY62OWI5SGSTZLIQUMXTTVME"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "Y4UHVLFIZZZK7ENDYZ4O3ZZI2QWUJI37"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "Z2KDRL4ELOCDALT3OSNUK65Z2KPOWGUL"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "OWRQKSCBLRUZXYXLXIDATUK6UTG3CPVV"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "XQLSEGNYPBMVK35ZMDTVN5GFOZB46WJJ"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "M3KVKGRB2WVWOZXN437EMF2MS36G75IR",
            "Comment"    : "This is genuinely my Twitter TOTP secret - although the period should be 30. But what's the password? There's a clue somewhere in this source code!",
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "3EMER2B6YXIFMMAY5XBYLNF4NSEGJXCU"
        },
        {
            "algorithm"  : "SHA1",
            "digits"     :  6,
            "period"     : 15,
            "secret"     : "ZML6O5K7QSVFE5QIWNFFT7BIZI7PBHNV"
        }
    ]


var i = 0;

otpData.forEach (
    item => {
        //  Add OTP
        otps[i] = item;
        i++;
    }
);

//  Generate TOTP codes
async function update() {
    for (var i = 0; i < otps.length; i++){
            //  Convert the algorithm
            //  The algorithm name is different for TOTP and Web Crypto(!)
            algorithm = "SHA-1";
            
            document.getElementById( "otp" + i).innerHTML = await generateTOTP( 
                otps[i]["secret"], 
                otps[i]["period"], 
                otps[i]["digits"], 
                algorithm
            );
    }
}
//  Update every second
setInterval(update, 1000);

</script>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:🫠">
<p>🫠&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🫠" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🖕">
<p>🖕&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🖕" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🙃">
<p>🙃&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🙃" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:dox">
<p>The neologism "doxing" hadn't yet been invented.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:dox" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:back">
<p>As was written by the prophets: "<a href="https://lkml.iu.edu/hypermail/linux/kernel/9607.2/0292.html">Only wimps use tape backup: <em>real</em> men just upload their important stuff on ftp, and let the rest of the world mirror it</a>"&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:back" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:rat">
<p>I in no way imply that I am rational.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:rat" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:bro">
<p>Just one more factor, that'll fix security, just gotta add one more factor bro.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:bro" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:🤯">
<p>This is left as an exercise for the reader.&nbsp;<a href="https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/#fnref:🤯" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=59334&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/04/fobcam-25-all-my-mfa-tokens-on-one-page/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Towards a test-suite for TOTP codes]]></title>
		<link>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/</link>
					<comments>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 02 Mar 2025 12:34:39 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[HTOP]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=58593</guid>

					<description><![CDATA[Because I&#039;m a massive nerd, I actually try to read specification documents. As I&#039;ve ranted ad nauseam before, the current TOTP spec is irresponsibly obsolete.  The three major implementations of the spec - Google, Apple, and Yubico - all subtly disagree on how it should be implemented. Every other MFA app has their own idiosyncratic variants. The official RFC is infuriatingly vague. That&#039;s no…]]></description>
										<content:encoded><![CDATA[<p>Because I'm a massive nerd, I <em>actually try to read</em> specification documents. As I've ranted <i lang="la">ad nauseam</i> before, the current TOTP<sup id="fnref:totp"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#fn:totp" class="footnote-ref" title="Time-based One Time Passwords. Not the TV show you remember from your youth, grandad." role="doc-noteref">0</a></sup> spec is <a href="https://shkspr.mobi/blog/2025/02/the-least-secure-totp-code-possible/">irresponsibly obsolete</a>.</p>

<p>The three major implementations of the spec - <a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Google</a>, <a href="https://developer.apple.com/documentation/authenticationservices/securing-logins-with-icloud-keychain-verification-codes#3795996">Apple</a>, and <a href="https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html">Yubico</a> - all subtly disagree on how it should be implemented. Every other MFA app has their own idiosyncratic variants. The <a href="https://datatracker.ietf.org/doc/html/rfc6238">official RFC is infuriatingly vague</a>. That's no good for a security specification. Multiple implementations are great, multiple interpretations are not.</p>

<p>So I've <a href="https://edent.codeberg.page/TOTP_Test_Suite/">built a nascent test suite</a> - you can use it to see if your favourite app can correctly implement the TOTP standard.</p>

<p><a href="https://edent.codeberg.page/TOTP_Test_Suite/"><img src="https://shkspr.mobi/blog/wp-content/uploads/2025/03/TOTP-Tests-fs8.png" alt="Screenshot showing a QR code and numeric codes." width="1024" height="813" class="aligncenter size-full wp-image-58598"></a></p>

<p>Please do contribute tests and / or feedback.</p>

<p>Here's what the standard <em>actually</em> says - see if you can find apps which don't implement it correctly.</p>

<h2 id="background"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#background">Background</a></h2>

<p>Time-based One Time Passwords are based on HOTP - HMAC-Based One-Time Password.</p>

<p>HOTP uses counters; a new password is regularly generated. TOTP uses time as the counter. At the time of writing this post, there have been about 1,740,800,000 seconds since the UNIX Epoc. So a TOTP with an period of 30 seconds is on counter (1,740,800,000 ➗ 30) = 58,026,666.  Every 30 seconds, that counter increments by one.</p>

<h3 id="number-of-digits"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#number-of-digits">Number of digits</a></h3>

<p>How many digits should your 2FA token have? Google says 6 or 8. YubiCo graciously allows 7. Why those limits? Who knows!?</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.4">The HOTP specification gives an <em>example</em> of 6 digits</a>.  The example generates a code of <code>0x50ef7f19</code> which, in decimal, is <code>1357872921</code>. It then takes the last 6 digits to produce the code <code>872921</code>.</p>

<p>The TOTP RFC says:</p>

<blockquote><p>Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values</p>

<p><a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">1.2. Background</a></p></blockquote>

<p>But doesn't say how far to truncate.</p>

<p>There's nothing I can see in the spec that <em>prevents</em> an implementer using all 10.  The HOTP spec, however, <em>does</em> place a minimum requirement - but no maximum:</p>

<blockquote><p>Implementations MUST extract a 6-digit code at a minimum and possibly 7 and 8-digit code.
Depending on security requirements, Digit = 7 or more SHOULD be considered in order to extract a longer HOTP value.
<a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.3">RFC 4226 - 5.3. Generating an HOTP Value</a></p></blockquote>

<p>(As a minor point, the first digit is restricted to 0-2, so being 10 digits long isn't significantly stronger than 9 digits.)</p>

<p>Is a 4 digit code acceptable? The security might be weaker, but the usability is greater. Most apps will allow a <em>one</em> digit code to be returned. If no digits are specified, what should the default be?</p>

<h3 id="algorithm"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#algorithm">Algorithm</a></h3>

<p>The given algorithm in the HOTP spec is SHA-1.</p>

<blockquote><p>In order to create the HOTP value, we will use the HMAC-SHA-1 algorithm
<a href="https://datatracker.ietf.org/doc/html/rfc4226#section-5.2">RFC 4226 - 5.2.  Description</a></p></blockquote>

<p>As we now know, SHA-1 has some fundamental weaknesses. The spec comments (perhaps somewhat naïvely) about SHA-1:</p>

<blockquote><p>The new attacks on SHA-1 have no impact on the security of HMAC-SHA-1.
<a href="https://datatracker.ietf.org/doc/html/rfc4226#appendix-B.2">RFC 4226 - B.2.  HMAC-SHA-1 Status</a></p></blockquote>

<p>I daresay that's accurate. But the TOTP authors disagree and allow for some different algorithms to be used. The specification for HMAC says:</p>

<blockquote><p>HMAC can be used with <em>any</em> iterative cryptographic hash function, e.g., MD5, SHA-1
[Emphasis added]
<a href="https://datatracker.ietf.org/doc/html/rfc2104">RFC 2104 - HMAC: Keyed-Hashing for Message Authentication</a></p></blockquote>

<p>So most TOTP implementation allow SHA-1, SHA-256, and SHA-512.</p>

<blockquote><p>TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions […] instead of the HMAC-SHA-1 function that has been specified for the HOTP computation
<a href="https://datatracker.ietf.org/doc/html/rfc6238#section-1.2">RFC 6238 - TOTP: Time-Based One-Time Password Algorithm</a></p></blockquote>

<p>But the HOTP spec goes on to say:</p>

<blockquote><p>Current candidates for such hash functions include SHA-1, MD5, RIPEMD-128/160.
These different realizations of HMAC will be denoted by HMAC-SHA1, HMAC-MD5, HMAC-RIPEMD
<a href="https://datatracker.ietf.org/doc/html/rfc2104#section-1">RFC 2104 - Introduction</a></p></blockquote>

<p>So, should your TOTP app be able to handle an MD5 HMAC, or even SHA3-384? Will it?  If no algorithm is specified, what should the default be?</p>

<h3 id="period"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#period">Period</a></h3>

<p>As discussed, this is what increments the counter for HOTP. The <a href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format">Google Spec</a> says:</p>

<blockquote><p>The period parameter defines a period that a TOTP code will be valid for, in seconds. The default value is 30.</p></blockquote>

<p>The TOTP RFC says:</p>

<blockquote><p>We RECOMMEND a default time-step size of 30 seconds
<a href="https://datatracker.ietf.org/doc/html/rfc6238#section-5.2">5.2. Validation and Time-Step Size</a></p></blockquote>

<p>It doesn't make sense to have a negative number of second. But what about one second? What about a thousand? Lots of apps artificially restrict TOTP codes to 15, 30, or 60 seconds. But there's no specification to define a maximum or minimum value.</p>

<p>A user with mobility difficulties or on a high-latency connection probably wants a 5 minute validity period. Conversely, machine-to-machine communication can probably be done with a single-second (or lower) time period.</p>

<h3 id="secret"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#secret">Secret</a></h3>

<p>Google says the secret is</p>

<blockquote><p>an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted.</p></blockquote>

<p>Whereas Apple says it is:</p>

<blockquote><p>An arbitrary key value encoded in Base32. Secrets should be at least 160 bits.</p></blockquote>

<p>Can a shared secret be a single character? What about a thousand? Will padding characters cause a secret to be rejected or can they be safely stripped?</p>

<h3 id="label"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#label">Label</a></h3>

<p>The label allows you to have multiple codes for the same service. For example <code>Big Bank:Personal Account</code> and <code>Big Bank:Family Savings</code>.  The Google spec is slightly confusing:</p>

<blockquote><p>The issuer prefix and account name should be separated by a literal or url-encoded colon, and optional spaces may precede the account name. Neither issuer nor account name may themselves contain a colon.</p></blockquote>

<p>What happens if they are <em>not</em> URl encoded? What about Matrix accounts which use a colon in their account name? Why are spaces allowed to precede the account name? Is there any practical limit to the length of these strings?</p>

<p>If no label is specified, what should the default be?</p>

<h3 id="issuer"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#issuer">Issuer</a></h3>

<p>Google says this parameter is:</p>

<blockquote><p><strong>Strongly Recommended</strong> The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal.</p></blockquote>

<p>Apple merely says:</p>

<blockquote><p>The domain of the site or app. The password manager uses this field to suggest credentials when setting up a new code generator.</p></blockquote>

<p>Yubico equivocates with</p>

<blockquote><p>The issuer parameter is recommended, but it can be absent. Also, the issuer parameter and issuer string in label should be equal.</p></blockquote>

<p>If it isn't a domain, will Apple reject it? What happens if the issuer and the label don't match?</p>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#next-steps">Next Steps</a></h2>

<ul>
<li>If you're a user, <a href="https://codeberg.org/edent/TOTP_Test_Suite">please contribute tests</a> or give feedback.</li>
<li>If you're a developer, please check your app conforms to the specification.</li>
<li>If you're from Google, Apple, Yubico, or another security company - wanna help me write up a proper RFC so this doesn't cause issues in the future?</li>
</ul>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:totp">
<p>Time-based One Time Passwords. Not the TV show you remember from your youth, grandad.&nbsp;<a href="https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/#fnref:totp" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=58593&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2025/03/towards-a-test-suite-for-totp-codes/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Should you enable TOTP *only* authentication?]]></title>
		<link>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/</link>
					<comments>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 04 Oct 2024 11:34:24 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=53016</guid>

					<description><![CDATA[Here&#039;s a &#34;fun&#34; thought experiment. Imagine a website which let you sign in using only your username and TOTP code.  No passwords. No magic links emailed to you. No FIDO tokens. No codes via SMS. Just a TOTP generated and displayed on your device.  Is that useful? Sensible? Practical?  It&#039;s certainly technically possible. Store the username, store the TOTP seed, done. Your users can now log in. …]]></description>
										<content:encoded><![CDATA[<p>Here's a "fun" thought experiment. Imagine a website which let you sign in using only your username and TOTP code.</p>

<p>No passwords. No magic links emailed to you. No FIDO tokens. No codes via SMS. <em>Just</em> a TOTP generated and displayed on your device.</p>

<p>Is that useful? Sensible? Practical?</p>

<p>It's certainly technically <em>possible</em>. Store the username, store the TOTP seed, done. Your users can now log in.</p>

<p>Is it <em>useful</em>? Well, it would force users to not reuse passwords they've used elsewhere. That prevents one class of security issue. If another service gets hacked, attackers can't use those credentials with your service. If you get hacked, there are no passwords stored.</p>

<p>As for <em>practical</em>? I already have 60 TOTP codes! (That's up from <a href="https://shkspr.mobi/blog/2020/08/i-have-4-2fa-coverage/">30 a few years ago</a>). Scrolling through those codes is no harder than scrolling through my password manager.</p>

<p>So, <em>sensible</em>? This all depends on your risk tolerance.</p>

<ul>
<li>A 6 digit TOTP code has a million combinations. If your service has no rate limiting, that's trivial for an attacker to brute-force.</li>
<li>An attacker <em>might</em> get lucky and score a literal one-in-a-million hit.</li>
<li>Shoulder surfing attacks are easier if the password is only 6 digits (although harder with a short time-window).</li>
</ul>

<p>Should you build an authentication mechanism like this?</p>

<p>Ehhhh… I'm going to go with "mostly no, except in limited circumstances".  It might make life slightly easier for some users.  But I feel inherently <em>icky</em> about having such a short password, even if it does regularly rotate.  If this is a low-value service without sensitive information, it <em>might</em> be useful. But for everything else, I think it is a silly ideas.</p>

<p><a href="https://mastodon.social/@Edent/113106727728186564">Further discussion on Mastodon</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=53016&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/10/should-you-enable-totp-only-authentication/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Is it OK to share 2FA secrets?]]></title>
		<link>https://shkspr.mobi/blog/2024/08/is-it-ok-to-share-2fa-secrets/</link>
					<comments>https://shkspr.mobi/blog/2024/08/is-it-ok-to-share-2fa-secrets/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 11 Aug 2024 11:34:01 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=51197</guid>

					<description><![CDATA[Yeah. Yeah, I reckon so. Under the right circumstances.  Multi-Factor Authentication (MFA, 2FA, TOTP, whatever you want to call it) is pretty nifty. You scan a QR code and your phone will continually generate a set of one-time passwords which are synchronised with a remote server.  There&#039;s nothing stopping multiple people from scanning that QR code! They will each have the same password displayed …]]></description>
										<content:encoded><![CDATA[<p>Yeah. Yeah, I reckon so. Under the right circumstances.</p>

<p>Multi-Factor Authentication (MFA, 2FA, TOTP, whatever you want to call it) is pretty nifty. You scan a QR code and your phone will continually generate a set of one-time passwords which are synchronised with a remote server.</p>

<p>There's nothing stopping <em>multiple</em> people from scanning that QR code! They will each have the same password displayed at the same time.</p>

<p>I've found this to be useful in a few situations.</p>

<p>If my wife and I have access to the same account, and it doesn't allow individual sign-ins, then we share a username, password, and MFA code. That only works in a high trust environment. If your marriage is not high trust, you may need a different solution.</p>

<p>For a Big Work Project™ we had several people on-call. In case of emergency, someone would ring a "group hunt" number. Any one of the team could pick up. In order to authenticate both the caller and the answerer, all participants had the same TOTP code stored on their phones. That was more sensible than having a dozen different passwords.</p>

<p>There are risks, of course.</p>

<ul>
<li>Giving multiple people access to a system increases the risk one of them will be hacked, phished, or attacked.</li>
<li>Having a secret on multiple devices means multiple chances for it to be leaked.</li>
<li>Revoking and reissuing keys is more difficult with multiple people.</li>
<li>It <em>feels</em> icky.</li>
</ul>

<p>There's nothing which technically stops you backing up or sharing your MFA secrets. But you need to be really sure you understand the risks.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=51197&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/08/is-it-ok-to-share-2fa-secrets/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Password Resets in an Age of MFA]]></title>
		<link>https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/</link>
					<comments>https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 01 Jul 2024 11:34:05 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[CyberSecurity]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[passwords]]></category>
		<category><![CDATA[totp]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=51014</guid>

					<description><![CDATA[Recently, WordPress got in contact with me to say they suspect that my password was exposed in some sort of data breach. Well, it&#039;s a day ending with a &#34;y&#34; - so of course some scumbag has pilfered my digital identity.  WordPress mandated that I change my password. But was that really necessary?  Firstly, the password was uniquely generated by my password manager. It isn&#039;t re-used anywhere else.…]]></description>
										<content:encoded><![CDATA[<p>Recently, WordPress got in contact with me to say they suspect that my password was exposed in some sort of data breach. Well, it's a day ending with a "y" - so of course some scumbag has pilfered my digital identity.</p>

<p>WordPress mandated that I change my password. But was that really necessary?</p>

<p>Firstly, the password was uniquely generated by my password manager<sup id="fnref:password"><a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fn:password" class="footnote-ref" title="It was w@&amp;7%GUznK#9^}<S5 if you must know." role="doc-noteref">0</a></sup>. It isn't re-used anywhere else. So there is no chance of hackers breaking in to my email, bank, or OnlyFans account<sup id="fnref:OF"><a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fn:OF" class="footnote-ref" title="Lots of weirdos want to buy videos of me recompiling Linux while in my pants. Who am I to judge?" role="doc-noteref">1</a></sup>.</p>

<p>Secondly, and more importantly, I have 2FA app which provides me with a TOTP code every time I want to log in. Even if the evil ne'erdowells have my username <em>and</em> password, they can't get in without the MFA code<sup id="fnref:2FA"><a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fn:2FA" class="footnote-ref" title="It is currently 194 685." role="doc-noteref">2</a></sup>.</p>

<p>So, should I change my password?</p>

<p>To understand this, it's worth considering the risks - both of action and inaction.</p>

<p>Changing a password isn't without risk.</p>

<ul>
<li>Perhaps some long-forgotten app or service relies on that password. If I change it, what will break?</li>
<li>Do I trust my password manager to give me a strong password?</li>
<li>What if the original email is a phishing attempt and I end up giving the baddies my credentials?</li>
<li>Can I be bothered spending the time maintaining this old account?</li>
</ul>

<p>As for the risk of inaction.</p>

<ul>
<li>Using my details, a miscreant <em>might</em> convince WordPress to disable MFA on my account.</li>
<li>If there was a breach, my MFA seed secret might also have been stolen.</li>
</ul>

<p>On balance… yeah, obviously I should change my password. It is a 30 second job with a decent password manager. But, I might argue, there isn't much <em>urgency</em> in doing so.</p>

<ul>
<li>A strong and unique password means there is no risk of collateral damage to other accounts.</li>
<li>The use of MFA adds an extra layer of protection which buys you time.</li>
</ul>

<p>Thankfully, we've moved on from the outdated advice to <a href="https://www.ncsc.gov.uk/collection/passwords/updating-your-approach#PasswordGuidance:UpdatingYourApproach-Don'tenforceregularpasswordexpiry">regularly change your password</a>.  Now we only have to change them when there's been a breach. Which, coincidentally, is every 30 days…</p>

<p>The future ain't what it used to be!</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:password">
<p>It was <code>w@&amp;7%GUznK#9^}&lt;S5</code> if you must know.&nbsp;<a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fnref:password" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:OF">
<p>Lots of weirdos want to buy videos of me recompiling Linux while in my pants. Who am I to judge?&nbsp;<a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fnref:OF" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:2FA">
<p>It is currently <code>194 685</code>.&nbsp;<a href="https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/#fnref:2FA" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=51014&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/07/password-resets-in-an-age-of-mfa/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Review: An NFC reader/writer with USB-C - ACR1252U-MF ★★★★⯪]]></title>
		<link>https://shkspr.mobi/blog/2024/02/review-an-nfc-reader-writer-with-usb-c-acr1252u-mf/</link>
					<comments>https://shkspr.mobi/blog/2024/02/review-an-nfc-reader-writer-with-usb-c-acr1252u-mf/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 24 Feb 2024 12:34:04 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[gadget]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[nfc]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[rfid]]></category>
		<category><![CDATA[usb-c]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=49611</guid>

					<description><![CDATA[I needed to read and write NFC cards on Linux. I only buy USB-C peripherals now, so I found the brilliantly named &#34;ACR1252U-MF&#34; which appears to be the only USB-C reader on the market. Total cost was about £35 on eBay.  It&#039;s a cheap and light plastic box with a short USB cord. When you plug it in, there&#039;s a flashing light which can&#039;t be disabled. When it is powered up, or it detects and NFC chip, …]]></description>
										<content:encoded><![CDATA[<p>I needed to read and write NFC cards on Linux. I only buy USB-<strong>C</strong> peripherals now, so I found the brilliantly named "<a href="https://www.acs.com.hk/en/products/342/acr1252u-usb-nfc-reader-iii-nfc-forum-certified-reader/">ACR1252U-MF</a>" which appears to be the only USB-C reader on the market. Total cost was about £35 on eBay.</p>

<p>It's a cheap and light plastic box with a short USB cord. When you plug it in, there's a flashing light which can't be disabled. When it is powered up, or it detects and NFC chip, it makes this weird and scratchy beep:</p>

<p></p><figure class="audio">
	<figcaption>🔊</figcaption>
	
	<audio controls="" loading="lazy" src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/ACR1252u-MF-Beep.mp3">
		<p>💾 <a href="https://shkspr.mobi/blog/wp-content/uploads/2024/02/ACR1252u-MF-Beep.mp3">Download this audio file</a>.</p>
	</audio>
</figure><p></p>

<p>On Linux, it shows up as: <code>072f:223b Advanced Card Systems, Ltd ACR1252 Dual Reader</code></p>

<p>To get it working, install <a href="https://pcsc-tools.apdu.fr/">PCSC Tools</a> and the <a href="https://linux.die.net/man/8/pcscd">PCSC Daemon</a>:</p>

<p><code>sudo apt install pcsc-tools pcscd</code></p>

<p>To start the daemon:</p>

<p><code>service pcscd start</code></p>

<p>Running <code>pcsc_scan</code> detected the reader as <em>two</em> readers - PICC and SAM</p>

<pre><code class="language-terminal">Using reader plug&amp;#039;n play mechanism
Scanning present readers...
0: ACS ACR1252 1S CL Reader [ACR1252 Dual Reader PICC] 00 00
1: ACS ACR1252 1S CL Reader [ACR1252 Dual Reader SAM] 01 00
</code></pre>

<p>Putting tokens on and off the reader showed them being detected and removed.</p>

<p>Despite my best efforts, I was <a href="https://github.com/nfc-tools/libnfc/issues/658">unable to get this working with <code>libnfc</code></a>.</p>

<pre><code class="language-txt">nfc-list uses libnfc 1.8.0
No NFC device found.
</code></pre>

<p>For reading and writing basic NDEF tags, I used <a href="https://www.wakdev.com/en/apps/nfc-tools-pc-mac.html">Wakdev's NFC tools</a>, I was also able to use various Python scripts like <a href="https://github.com/Giraut/pcsc-ndef">PCSC NDEF</a></p>

<p>It also worked with a <a href="https://github.com/BryanJacobs/fido2-hid-bridge">FIDO2 / HID Bridge</a> so I could use an MFA token.</p>

<p>There's <a href="https://www.acs.com.hk/en/driver/342/acr1252u-usb-nfc-reader-iii-nfc-forum-certified-reader/">lots of documentation about the reader and its API</a> as well as some <a href="https://www.acs.com.hk/en/utility-tools/">official ACS Linux tools</a>. In theory it supports firmware update - although none have been released.</p>

<p>It's a cheap and cheerful device. It would be nice if there were a way to stop the flashing LED and crappy buzzer.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=49611&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/02/review-an-nfc-reader-writer-with-usb-c-acr1252u-mf/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Giving the finger to MFA - a review of the Z1 Encrypter Ring from Cybernetic ★★★★☆]]></title>
		<link>https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/</link>
					<comments>https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 23 Feb 2024 12:34:17 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[2fa]]></category>
		<category><![CDATA[fido]]></category>
		<category><![CDATA[gadget]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[nfc]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[rfid]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=49592</guid>

					<description><![CDATA[I have mixed feelings about Multi-Factor Authentication. I get why it is necessary to rely on something which isn&#039;t a password but - let&#039;s be honest here - it is a pain juggling between SMS, TOTP apps, proprietary apps, and magic links.  I&#039;m also not a fan of PassKeys. It feels weird to me that my computer is the password. I get the theoretical way it works - but it rubs me up the wrong way.  So, …]]></description>
										<content:encoded><![CDATA[<p>I have mixed feelings about Multi-Factor Authentication. I get why it is necessary to rely on something which isn't a password but - let's be honest here - it is a pain juggling between SMS, TOTP apps, proprietary apps, and magic links.</p>

<p>I'm also not a fan of PassKeys<sup id="fnref:terminology"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fn:terminology" class="footnote-ref" title="FIDO2? U2F? MFA? PassKeys? Some of these are technologies and some are marketing terms. In most cases it is transparent to the user. They type in their username and password, then they have to…" role="doc-noteref">0</a></sup>. It feels weird to me that my computer <em>is</em> the password. I get the theoretical way it works - but it rubs me up the wrong way.</p>

<p>So, Yubikeys? <a href="https://shkspr.mobi/blog/2017/11/a-grumpy-look-at-using-a-yubico-neo-nfc-on-ubuntu-android/">I find them an annoyance</a>. I never have my keys to hand - which sort of defeats the purpose of them.</p>

<p>A little while ago, I wondered "<a href="https://shkspr.mobi/blog/2022/02/where-are-the-u2f-rings/">Where are the U2F Rings?</a>" If I could have a <em>wearable</em> MFA token, that would solve many of my issues<sup id="fnref:issues"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fn:issues" class="footnote-ref" title="Technical issues. Obviously my many personal issues remain load-bearing." role="doc-noteref">1</a></sup>.</p>

<p>Enter the <a href="https://getcybernetic.com/product/ring/">Cybernetic Z1 Encrypter Ring</a>. It is a US$300 zirconia ring with a built-in range of JavaCard-based NFC apps - including the ability to unlock your Tesla<sup id="fnref:tesla"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fn:tesla" class="footnote-ref" title="I don't have a Tesla to test it on. And I'd rather keep it that way!" role="doc-noteref">2</a></sup>. It is powered by the <a href="https://vivokey.com/apex/">VivoKey Apex chip</a> (NXP JCOP 4 P71) which provides all the security and functionality. Your money also gets you an NFC reader/writer which connects to your computer via USB.  The team have sent me a demo version of the ring to review on the proviso that I give them feedback.</p>

<h2 id="demo"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#demo">Demo</a></h2>

<p>Here's a quick video showing how it works:</p>

<iframe title="Review: Cybernetic's Z1 Encrypter Ring - FIDO2, U2F, PassKey" width="560" height="315" src="https://tube.tchncs.de/videos/embed/84a5f19d-fe75-4b6a-baaa-970c9767d8c3" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups"></iframe>

<h2 id="the-good"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#the-good">The Good</a></h2>

<p>It works! Seriously, in a world of vapourware and vaguely-worded Kickstarters, it is refreshing to have a product which actually delivers. I was able to enrol it on my BitWarden account and then use it to log in - all via my Android phone. Similarly, I tested it working with Amazon, BitWarden, CodeBerg, Discord, Gandi, GitLab, GoDaddy, Google, PorkBun, Proton, WordPress and a few others.</p>

<p>It's a good looking, plainly designed, unibody ring. It is waterproof and survived the daily abuse I give my hands.  It was washed with soap and blasted with a hand-dryer and it kept on chugging. No need to recharge it either - NFC runs off the power of radio waves like magic.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/cybernetic-black-gloss-side-b-1.webp" alt="A plain black ring. What secrets does it contain within?" width="512" height="512" class="aligncenter size-full wp-image-49594">

<p>It is completely smooth, no built in scanners or LEDs or power-ports. The antenna appears to be all the way around the ring - so you can use either side of your finger on a scanner.</p>

<p>There is an <a href="https://play.google.com/store/apps/details?id=com.vivokey.apexmanager.cybernetic">Android app</a> which you can use to send information to the ring. That's designed for being able to share contact details and has a generous 4KB of storage<sup id="fnref:4kb"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fn:4kb" class="footnote-ref" title="Not a typo. NFC is designed for low power and fairly low speed. Most commercial NFC tags have about 500 bytes of storage. The memory on this ring will let you share up to 32KB of data - if you remove…" role="doc-noteref">3</a></sup>.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Android-app-fs8.png" alt="Android app with various options greyed out." width="540" height="966" class="aligncenter size-full wp-image-49602">

<p>But, the nice thing is, <strong>you don't <em>need</em> the app!</strong> By default the ring will work as a FIDO2 token suitable for logging in to a variety of services.</p>

<p>The code on the Ring is (somewhat) Open Source. You can write your own JavaCard applets and load them on to the ring.</p>

<h2 id="the-bad"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#the-bad">The Bad</a></h2>

<p>It works well... until it doesn't. Mostly this is a criticism of FIDO2. I initially was unable to use the ring with GitHub:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Something-Went-Wrong-fs8.png" alt="Android pop up saying &quot;Something went wrong&quot;." width="540" height="951" class="aligncenter size-full wp-image-49600">
I tried both Firefox and Chrome but got the same error.  Similarly, CoinBase wouldn't register the key and didn't tell me why.</p>

<p>I contacted the Ring's manufacturer and they sent me details of a <a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#updates">firmware update</a> which claimed to fixed the issue.</p>

<p>Google worked - but gave me this rather weird default name and icon:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Google-Account-fs8.png" alt="Google account page showing an Apple logo and the name iCloud keychain." width="540" height="674" class="aligncenter size-full wp-image-49601">
I was able to rename it, but the icon can't be changed.</p>

<p>Amazon had the same issue, but with no way to rename.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Amazon-passkey-fs8.png" alt="Screenshot showing the Passkey has been added - but it is called iCloud Keychain." width="540" height="708" class="aligncenter size-full wp-image-49633">

<p>Both LinkedIn and WhatsApp would only let me create a phone-based PassKey. They didn't give me a prompt to scan my NFC ring.</p>

<p>NFC <em>only</em> is also a bit of a limitation. Until every laptop comes with built-in NFC, you'll need to use a dongle / reader if you want to use the ring.  For a phone or tablet with NFC, you're fine.  Well, as long as you know where your phone's NFC reader is!</p>

<p>The Android app isn't open source, which feels like a bit of a missed opportunity. It is pretty bare-bones, only providing the ability to add contact details and see how much free storage and RAM there is. In the future, the app promises to offer "Smart PGP" and a few other services.</p>

<p>The contact card stuff is a bit underwhelming. Rather than embed a VCARD, it takes users to a separate website which has your contact details on it.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Social-Network-fs8.png" alt="Screenshot of a website with a pixelated image of my face and some contact details." width="540" height="592" class="aligncenter size-full wp-image-49603">

<p>Weirdly, it zips the content of your contact details and uses them to populate the website with data. Because there's only a limited amount of space available, contact images end up very pixellated.  The website also uses external JavaScript without using SRI - which isn't what I'd expect from a security focussed company.</p>

<p>If you use a 3rd party NFC app, you can change the NDEF share to be <em>any</em> URl you want.  I think that's probably a sensible thing to do.</p>

<p>Obviously, $300 is a chunk of change. You can <a href="https://amzn.to/49rsPMT">buy a basic U2F USB/NFC <strong>key</strong> for £20 - £50</a>. So, with this, you're paying a higher price for a small-run product with a niche form-factor.</p>

<h2 id="the-ugly"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#the-ugly">The Ugly?</a></h2>

<p>Do you want to wear jewellery? The Z1 is plain black and unobtrusive - unlike the garish designs of some fashion rings - but perhaps a few different styles and colours would be nice?</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Ring-height.jpg" alt="Photo of my fingers curled up so you can see the height of the ring." width="1024" height="1024" class="aligncenter size-full wp-image-49604">

<p>I already wear a wedding ring, so having another to wear wasn't too much of an adjustment.  The ring comes in a number of US ring sizes, so you may need to compensate if you're used to a different sizing system. However, it is a bit of a chunky beast. You will certainly notice it while wearing it.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/Ring-width.jpg" alt="Photo of my fingers stretched out so you can see the width of the ring." width="1024" height="1024" class="aligncenter size-full wp-image-49605">

<p>Would an attacker rip it off your finger or even chop your finger off? It is a niche risk - but if you're using this to digitally safeguard your billions of crypto-riches, worth thinking about.</p>

<h2 id="updates"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#updates">Updates</a></h2>

<p>The Z1 Encrypter runs JavaCard applets so, in theory, you can load any compatible app onto it. By default, it runs <a href="https://github.com/BryanJacobs/FIDO2Applet">Bryan Jacobs' FIDO2Applet</a>.  It recently received <a href="https://github.com/BryanJacobs/FIDO2Applet/commit/1f406ec383f7b447c7752d4d35b2f3bbd3c079d3">an update</a> which should make it work with GitHub.</p>

<p>To install or update apps, you'll need the Fidesmo <a href="https://play.google.com/store/apps/details?id=com.fidesmo.sec.android">Android app</a> or <a href="https://apps.apple.com/us/app/fidesmo/id1504891446">iOS app</a>.</p>

<p><strong>WARNING!</strong> Before installing a new app, you have to destroy the old one. This will wipe <em>all</em> your previous registrations.</p>

<p>However, I just couldn't get this to work. I tried using the Fidesmo app to uninstall the Tesla applet - but it failed.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2024/02/service-failed-uninstalling-fs8.png" alt="Screenshot of the Fidesmo app saying &quot;Service Failed Uninstalling&quot;." width="540" height="731" class="aligncenter size-full wp-image-49657">

<p>Despite it asking me to uninstall again, there was no option to do so.</p>

<p>I find it a bit weird that the Ring relies on a 3rd party app to do this. I'd much rather see it built into the same app which controls the ring.</p>

<h2 id="security"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#security">Security</a></h2>

<p>By default, the ring has no password set on its internal memory.  That means you can write whatever content you want to the NDEF share. Of course, this means someone sat next to you can <em>also</em> change your saved URl!  If you use the Fidesmo app, you can lock the contents of the share. Once locked it cannot be overwritten unless you destroy the applet.</p>

<p>So I was able to change the default URl to one I controlled, and I was able to lock it.</p>

<p>But <em>anyone</em> with the Fidesmo app can delete <em>any</em> applet on your ring. Simply open the app, tap the phone against the ring to read the data, select the app you want to delete, and hold the phone against the ring for a few seconds.</p>

<p>It isn't unobtrusive. You'd probably notice someone clutching your hand for a several seconds. But you probably wouldn't notice if you were asleep.</p>

<p>The only damage is rendering your PassKey inoperable. So you would have to revert back to using a different 2FA method. An attacker couldn't steal your data, but they could provide a denial of service attack on you.</p>

<p>It would be great if the ring came with a password. However, there is the risk that if you lost your own password, you'd be unable to write data to it.</p>

<p>I am unqualified to audit the hardware security. If an attacker had physical access to the Ring, could they crack it open and extract the keys from hardware? I don't know.</p>

<h2 id="linux-support-open-source"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#linux-support-open-source">Linux Support &amp; Open Source</a></h2>

<p>The Cybernetic website says the Z1 supports "iOS, Android, Windows. MacOS coming June 2024."  But how well does it work with Linux?</p>

<p>There are <a href="https://github.com/VivoKey">several open source tools repositories available from VivoKey</a> - although none specifically related to the ring.</p>

<p>I took a look at a bunch of <a href="https://ccid.apdu.fr/ccid/section.html">compatible readers</a> and got the ACR1252u-MF (full review later). There are a couple of Linux utilities which claim to work as NFC U2F readers - but the only one I could get working was Bryan Jacob's <a href="https://github.com/BryanJacobs/fido2-hid-bridge">FIDO2 HID Bridge</a>.  Installing was a bit of a faff (yay various Python incompatibilities) and using it means invoking an obscure command on the terminal. But... it worked!</p>

<p>I registered the ring on a service using my Android device, then I was able to sign in to the same service using Firefox on Linux!</p>

<p>Even better - I was <em>finally</em> able to register the ring with GitHub! And, once I'd registered it using Linux, I could sign on with Android. HASHTAG INTEROPERABILITY!</p>

<h2 id="the-broken"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#the-broken">The Broken</a></h2>

<p>And then I kinda broke it. Somehow, the Fidesmo app ended up <a href="https://forum.dangerousthings.com/t/cant-destroy-applets-with-fidesmo/21264/">locking the entire card</a>. Everything still worked - both NDEF and WebAuthN - but I couldn't update the firmware or applets. On the one hand, no one can wipe my OS! But on the other, I can't load new software or fix any bugs.</p>

<p>NFC is <em>fragile technology</em>. Send the wrong obscure command to the device and it will behave unpredictably.</p>

<h2 id="final-verdict"><a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#final-verdict">Final Verdict</a></h2>

<p>For a certain type of nerd, this is awesome. It doesn't have aggressive "geek-chic" branding - it just quietly lets you augment your body with a useful bit of tech.  Now I don't need to search for my key-ring every time I want to log into a secure service.</p>

<p>The flaws with this product are mostly to do with the ecosystem. Mostly.</p>

<p>U2F / FIDO2 / Whatever is pretty nifty technology. When it works, it is just like magic. Wave your hand near your phone and you are authenticated.</p>

<p>When it doesn't work, you might get stuck in a loop trying to work out why things are going wrong.  It's terrifyingly easy to accidentally break something.</p>

<p>FIDO2 is still a pain. Do you know <a href="https://www.beyondidentity.com/developers/blog/fido2-vs-u2f-whats-difference">the difference between CTAP1 and U2F, or how they relate to WebAuthn</a>? Does your favourite service <a href="https://2fa.directory/gb/">support 2FA at all</a>?  Are you happy running a Python script on the CLI if you want to log in?</p>

<p>But that's not the ring's fault. It is early days for the tech and there are teething troubles.</p>

<p>The built-in contact-card portion of the ring is a bit daft. Pointing users to a 3rd party site doesn't seem like the right call for the type of people who'll buy this. I'm glad it could be pointed to a site that I control - albeit by using a different app to write the data.</p>

<p>I got used to wearing the ring after a few days, and it was the exact size that I requested. Although it is chunky, it is a subtle piece of jewellery and unlikely to draw unwanted attention.  There are no LEDs or batteries to worry about.</p>

<p>Despite the teething issues and the price, I'm rather keen on this. Waving my hand next to my phone to exchange cryptographic information makes me feel part-way to being a cyborg-wizard.  Is this the future of wearable technology? I don't know - but it is rather fun.  I'm happy to be an early-adopter and to bash out the bugs in the tech.</p>

<p>If you want, VivoKey will also sell you an <a href="https://vivokey.com/spark/">NFC Implant</a> which you can inject under your skin and use as an MFA token.  Personally, I think I'll stick with the ring!</p>

<p>You can <a href="https://getcybernetic.com/">buy the ring directly from Cybernetic</a>.</p>

<div id="footnotes" role="doc-endnotes">
<hr aria-label="Footnotes">
<ol start="0">

<li id="fn:terminology">
<p>FIDO2? U2F? MFA? PassKeys? Some of these are technologies and some are marketing terms. In most cases it is transparent to the user. They type in their username and password, then they have to present another credential. That could be a code sent by a text message, or generated by an app. In this case, they present their NFC token.  Technically, a PassKey is designed to replace usernames and password - present your key and that's the only credential you'll need. The reality is that various sites use these terms interchangeably.&nbsp;<a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fnref:terminology" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:issues">
<p>Technical issues. Obviously my many personal issues remain load-bearing.&nbsp;<a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fnref:issues" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:tesla">
<p>I don't have a Tesla to test it on. And I'd rather keep it that way!&nbsp;<a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fnref:tesla" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

<li id="fn:4kb">
<p>Not a typo. NFC is designed for low power and fairly low speed. <a href="https://shkspr.mobi/blog/2020/06/gadget-review-ysshui-ntag215-nfc-tags/">Most commercial NFC tags have about 500 bytes of storage</a>. The memory on this ring will let you share up to 32KB of data - if you remove the other applets.&nbsp;<a href="https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/#fnref:4kb" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>

</ol>
</div>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=49592&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/02/giving-the-finger-to-mfa-a-review-of-the-z1-encrypter-ring-from-cybernetic/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
	</channel>
</rss>
