<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://genbox.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://genbox.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-10-31T12:33:37+00:00</updated><id>https://genbox.github.io/feed.xml</id><title type="html">Whatever Crossed My Mind</title><subtitle>Notes on software, algorithms, performance, and security by Ian Qvist.</subtitle><author><name>Ian Qvist</name></author><entry><title type="html">The history of gperf</title><link href="https://genbox.github.io/2025/03/the-history-of-gperf.html" rel="alternate" type="text/html" title="The history of gperf" /><published>2025-03-18T21:14:00+00:00</published><updated>2025-03-18T21:32:26+00:00</updated><id>https://genbox.github.io/2025/03/the-history-of-gperf</id><content type="html" xml:base="https://genbox.github.io/2025/03/the-history-of-gperf.html"><![CDATA[<p>In this post I'll document my research into the history of gperf. A copy of the historical documents and source code referenced in this post can be <a href="https://github.com/Genbox/gperf-archive" rel="noopener noreferrer" target="_blank">found here</a>.</p><p>If you have worked with hashing you have probably used gperf. It is a tool you give a list of keywords and outputs C/C++ code to lookup if a keyword is contained within the list. The lookup function is incredibly fast and looks like black magic.</p><p>In 1979 Richard J. Cichelli wrote an article titled <a href="https://dl.acm.org/doi/10.1145/358808.358813" rel="noopener noreferrer" target="_blank">Minimal Perfect Hash Functions Made Simple</a>. January 1980 it was published in Communications of the ACM, Volume 23, Issue 1. Back then Richard worked as a Research Manager for American Newspaper Publishers Association Research Institute, but was doing this as part of his own company <a href="https://www.newspapersystems.com/about-the-founders.html" rel="noopener noreferrer" target="_blank">Software Consulting Services (SCS)</a> which he ran with his wife Martha Cichelli until 2021.</p><div><br/></div><div>Today, Richard's article is known as <i>Cichelli's Method</i> and works by computing a hash based on the first and last character of the input, as well as the length of the input, then using that hash with an association table to generate a nearly-minimal perfect hash function. Cichelli describes two disadvantages in his article:</div><div><ol style="text-align: left;"><li>It requires that no two keys share length and the first and last characters</li><li>For lists with more than about 45 items, segmentation into sublists may be necessary</li></ol><div>These limitations will become important in the next paragraph.</div></div><div><br/></div><div>In December 1980, Gerhard Jaeschke and  G. Osterburg from IBM Scientific Center in Heidelberg, West Germany published an article in Communications of the ACM, Volume 23, Issue 12 titled <a href="https://dl.acm.org/doi/10.1145/359038.3084011" rel="noopener noreferrer" target="_blank">Technical Response to: On Cichelli's Minimal Perfect Hash Functions Method</a>. In the article, they determine that there exists an infinite number of keywords, on which Cichelli's perfect hash method (noted as Cichelli's Condition or CD) does not work. As a response to this, Richard adds a third disadvantage:</div><div><ol start="3"><li>For certain contrived lists of keys, it may be impossible to determine in advance whether this method will yield a minimal solution.</li></ol></div><div>Note: Gerhard Jaeschke has himself published several articles pertaining to minimal perfect hash functions which are quite interesting, but let's stay on the subject of gperf.</div><div><br/></div><div>In 1982 Charlie D. Havener wrote a tool called Perfect and in 1983 <a href="https://www.tuhs.org/Usenet/comp.sources.unix/1983-October/003584.html" rel="noopener noreferrer" target="_blank">posted it</a> in the Usenet newsgroup comp.sources.unix. It is based on Cichelli's method, and is the first public implementation, as the Pascal version written by Richard himself was never published. Charlie notes that Perfect was used to write a Lexical Analyzer Data Structure and posted in Appendix B in the article More on Minimal Perfect Hash Tables by Cook, Curtis R. and Oldehoeft, R. R.</div><div><br/></div><div>Back then Charlie worked with hardware and software design as a <a href="https://ecommons.cornell.edu/bitstream/1813/28000/1/086_08.pdf" rel="noopener noreferrer" target="_blank">senior principal engineer</a> at GenRad Inc. in the component test division in Bolton, Massachusetts. Later in 1988 he <a href="https://ecommons.cornell.edu/bitstream/1813/28039/1/090_07.pdf" rel="noopener noreferrer" target="_blank">taught computer science</a> at Boston University. Unfortunately, Charlie suffered from myelofibrosis (a rare blood cancer) and <a href="https://web.archive.org/web/20250318184140/https://www.legacy.com/us/obituaries/name/charles-havener-obituary?pid=178921677" rel="noopener noreferrer" target="_blank">died</a> November 10, 2012.</div><div><br/></div><div>In 1984 Keith Bostic <a href="https://www.usenetarchives.com/view.php?id=net.sources&amp;mid=PDQyMzRAc2Vpc21vLlVVQ1A%2B">posted</a> an improved version of Charlie's Perfect in the Usenet newsgroup net.sources. He highlights the limitations of the original implementation as mentioned above. Keith needed to hash more keywords than what was supported by Perfect, and therefore, rewrote Perfect to support his use case. He notes the following improvements:</div><div><ul style="text-align: left;"><li>No limit on the number of keywords</li><li>Much faster</li><li>No need to reorder the keywords</li><li>The ability to specify which keys to hash</li><li>It handles keywords that hash to identical values</li></ul><div>Instead of just taking the first and last characters, Keith's version allows the user to specify which characters to hash.</div></div><div><br/></div><div>In January 1989 Douglas C. Schmidt wrote version 1.1 of gperf in C++ while he was at University of California, Irvine, USA. As mentioned in the <a href="https://www.gnu.org/software/gperf/manual/gperf.html#Contributors" rel="noopener noreferrer" target="_blank">manual</a>, it was based on Keith's version of Perfect. In May 1989 Douglas made a C version which was published on comp.sources.unix.</div><div><br/></div><div>For many years, gperf was part of the libg++ library and the sources can still be found in <a href="https://ftp.tsukuba.wide.ad.jp/software/gcc/old-releases/libg++/" rel="noopener noreferrer" target="_blank">old releases</a>. The earliest release i could find was libg++-1.35.1. In August 2000, with the release of version 2.7, it was moved to be a separate project.</div>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[In this post I'll document my research into the history of gperf. A copy of the historical documents and source code referenced in this post can be found here.If you have worked with hashing you have probably used gperf. It is a tool you give a list of keywords and outputs C/C++ code to lookup if a keyword is contained within the list. The lookup function is incredibly fast and looks like black magic.In 1979 Richard J. Cichelli wrote an article titled Minimal Perfect Hash Functions Made Simple. January 1980 it was published in Communications of the ACM, Volume 23, Issue 1. Back then Richard worked as a Research Manager for American Newspaper Publishers Association Research Institute, but was doing this as part of his own company Software Consulting Services (SCS) which he ran with his wife Martha Cichelli until 2021.Today, Richard's article is known as Cichelli's Method and works by computing a hash based on the first and last character of the input, as well as the length of the input, then using that hash with an association table to generate a nearly-minimal perfect hash function. Cichelli describes two disadvantages in his article:It requires that no two keys share length and the first and last charactersFor lists with more than about 45 items, segmentation into sublists may be necessaryThese limitations will become important in the next paragraph.In December 1980, Gerhard Jaeschke and  G. Osterburg from IBM Scientific Center in Heidelberg, West Germany published an article in Communications of the ACM, Volume 23, Issue 12 titled Technical Response to: On Cichelli's Minimal Perfect Hash Functions Method. In the article, they determine that there exists an infinite number of keywords, on which Cichelli's perfect hash method (noted as Cichelli's Condition or CD) does not work. As a response to this, Richard adds a third disadvantage:For certain contrived lists of keys, it may be impossible to determine in advance whether this method will yield a minimal solution.Note: Gerhard Jaeschke has himself published several articles pertaining to minimal perfect hash functions which are quite interesting, but let's stay on the subject of gperf.In 1982 Charlie D. Havener wrote a tool called Perfect and in 1983 posted it in the Usenet newsgroup comp.sources.unix. It is based on Cichelli's method, and is the first public implementation, as the Pascal version written by Richard himself was never published. Charlie notes that Perfect was used to write a Lexical Analyzer Data Structure and posted in Appendix B in the article More on Minimal Perfect Hash Tables by Cook, Curtis R. and Oldehoeft, R. R.Back then Charlie worked with hardware and software design as a senior principal engineer at GenRad Inc. in the component test division in Bolton, Massachusetts. Later in 1988 he taught computer science at Boston University. Unfortunately, Charlie suffered from myelofibrosis (a rare blood cancer) and died November 10, 2012.In 1984 Keith Bostic posted an improved version of Charlie's Perfect in the Usenet newsgroup net.sources. He highlights the limitations of the original implementation as mentioned above. Keith needed to hash more keywords than what was supported by Perfect, and therefore, rewrote Perfect to support his use case. He notes the following improvements:No limit on the number of keywordsMuch fasterNo need to reorder the keywordsThe ability to specify which keys to hashIt handles keywords that hash to identical valuesInstead of just taking the first and last characters, Keith's version allows the user to specify which characters to hash.In January 1989 Douglas C. Schmidt wrote version 1.1 of gperf in C++ while he was at University of California, Irvine, USA. As mentioned in the manual, it was based on Keith's version of Perfect. In May 1989 Douglas made a C version which was published on comp.sources.unix.For many years, gperf was part of the libg++ library and the sources can still be found in old releases. The earliest release i could find was libg++-1.35.1. In August 2000, with the release of version 2.7, it was moved to be a separate project.]]></summary></entry><entry><title type="html">Escape the Crab Mentality</title><link href="https://genbox.github.io/2019/10/escape-crab-mentality.html" rel="alternate" type="text/html" title="Escape the Crab Mentality" /><published>2019-10-08T19:44:00+00:00</published><updated>2021-05-02T13:06:00+00:00</updated><id>https://genbox.github.io/2019/10/escape-crab-mentality</id><content type="html" xml:base="https://genbox.github.io/2019/10/escape-crab-mentality.html"><![CDATA[<p class="MsoNormal"><span lang="en-DK" style="color: black; line-height: 107%;">There is a well-known concept within psychology called Crab
mentality, which is a way of thinking best described by "If I can't have
it, neither can you". It is a mentality shared by millions around the
world, everywhere from small teams to local communities and all the way up to
large enterprises and countries.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">It is a way to survive when resources are scarce, as any
single entity in the group who consumes too much must be forced to live under
the same constraints as everyone else. However, the crab survivalist way of
thinking can often transcend constraints on resources, and factors such as envy
can exacerbate the mentality into a selfish ego-centric paradigm, which limits
other people's potential to accelerate beyond their peers and become better.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">It is from this mentality we hear stories like, "I want
to leave my local community to attend university, but our priest says I have to
stay and help my parents". What we see here is that our protagonist is not
allowed to leave, as the priest - a local community authority figure - would
rather have them stay and help their parents than attend a university.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">The fact that the priest interferes in the affairs of our
protagonist is rather odd, and from the simplified description we started out
with in the first paragraph, Crab mentality means "the priest can't go to
the university, so he doesn't want anyone to go". That is not the case,
but it is close! The difference between envy and Crab mentality is that in the
latter, our priest is not thinking of himself; he is thinking of himself and on
behalf of the whole community. He does not want our protagonist to leave.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">You see, when someone wants to better themselves, they often
realize that they can't become better while constrained by their current
situation, and the only solution is to look elsewhere for an open mind and
acceptance. However, at the same time, the local community will lose a member,
which is good at something, because they better themselves. It is kind of like
a catch-22 situation where the community doesn't want to lose somebody that is
good at something, but the person that is good at it feels like they are
constrained by their community and therefore want to leave.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">If you think about it, you might know someone who is caught
by this mentality, or you might be in this situation yourself. Some societies
even have this mentality </span><span lang="en-DK"><a href="https://en.wikipedia.org/wiki/%C7%83Kung_people#Hunting_rituals" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; widows: 2; word-spacing: 0px;" target="_blank"><span style="line-height: 107%;">ingrained into their culture</span></a></span><span lang="en-DK" style="color: black; line-height: 107%;"><span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"> , and others have </span></span><span lang="en-DK"><a href="https://en.wikipedia.org/wiki/Harrison_Bergeron#Plot" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; widows: 2; word-spacing: 0px;" target="_blank"><span style="line-height: 107%;">written satirical books</span></a></span><span lang="en-DK" style="color: black; line-height: 107%;"><span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"> to illustrate just how ridiculous this behavior is.</span><br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<br style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"/>
<span style="-webkit-text-stroke-width: 0px; float: none; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;">So if you are reading this: Don't be limited by your peers
and don't accept your current constraints if you can do better. Read what you
can, research what you need, and learn to become a better person through
knowledge.</span></span><span lang="en-DK"><o:p></o:p></span></p>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[There is a well-known concept within psychology called Crab mentality, which is a way of thinking best described by "If I can't have it, neither can you". It is a mentality shared by millions around the world, everywhere from small teams to local communities and all the way up to large enterprises and countries. It is a way to survive when resources are scarce, as any single entity in the group who consumes too much must be forced to live under the same constraints as everyone else. However, the crab survivalist way of thinking can often transcend constraints on resources, and factors such as envy can exacerbate the mentality into a selfish ego-centric paradigm, which limits other people's potential to accelerate beyond their peers and become better. It is from this mentality we hear stories like, "I want to leave my local community to attend university, but our priest says I have to stay and help my parents". What we see here is that our protagonist is not allowed to leave, as the priest - a local community authority figure - would rather have them stay and help their parents than attend a university. The fact that the priest interferes in the affairs of our protagonist is rather odd, and from the simplified description we started out with in the first paragraph, Crab mentality means "the priest can't go to the university, so he doesn't want anyone to go". That is not the case, but it is close! The difference between envy and Crab mentality is that in the latter, our priest is not thinking of himself; he is thinking of himself and on behalf of the whole community. He does not want our protagonist to leave. You see, when someone wants to better themselves, they often realize that they can't become better while constrained by their current situation, and the only solution is to look elsewhere for an open mind and acceptance. However, at the same time, the local community will lose a member, which is good at something, because they better themselves. It is kind of like a catch-22 situation where the community doesn't want to lose somebody that is good at something, but the person that is good at it feels like they are constrained by their community and therefore want to leave. If you think about it, you might know someone who is caught by this mentality, or you might be in this situation yourself. Some societies even have this mentality ingrained into their culture , and others have written satirical books to illustrate just how ridiculous this behavior is. So if you are reading this: Don't be limited by your peers and don't accept your current constraints if you can do better. Read what you can, research what you need, and learn to become a better person through knowledge.]]></summary></entry><entry><title type="html">Strings from a Security Perspective</title><link href="https://genbox.github.io/2019/06/strings-from-security-perspective.html" rel="alternate" type="text/html" title="Strings from a Security Perspective" /><published>2019-06-09T14:30:00+00:00</published><updated>2019-08-04T16:50:41+00:00</updated><id>https://genbox.github.io/2019/06/strings-from-security-perspective</id><content type="html" xml:base="https://genbox.github.io/2019/06/strings-from-security-perspective.html"><![CDATA[There are times when you have to store secrets in your application. You wish to do it securely, but how exactly would you do that? It is more problematic than you think, and if you don't design your application around certain concepts, you will end up with a security nightmare that is nearly impossible to solve.<br/>
<br/>
Let's take a look at an example. Here we are using the popular S3 client from Amazon's official AWS SDK for .NET:<br/>
<br/>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>AWSCredentials
cred = </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>new</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'> BasicAWSCredentials(</span><span style='color: #a31515; font-family: "consolas"; font-size: 9.5pt;'>"keyId"</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>, </span><span style='color: #a31515; font-family: "consolas"; font-size: 9.5pt;'>"secretAccessKey"</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>using</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'> (AmazonS3Client client = </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>new</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'> AmazonS3Client(cred))<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>{<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'><span style="mso-spacerun: yes;">    </span></span><span style='color: green; font-family: "consolas"; font-size: 9.5pt;'>//do something
with client</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'><o:p></o:p></span></div>
<div class="MsoNormal">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>}</span><o:p></o:p></div>
<br/>
The problem here is that you are forced to enter the secret access key as a string, and strings are not designed around security best practices. In .NET, strings are garbage collected, in contrast to integers, DateTime and other data types, which are not garbage collected. It is not the only problem with strings, but let's take one issue at the time.<br/>
<h2>
Strings are Garbage (Collected)</h2>
<div>
When you initialize a string like <span style='color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>string</span><span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'> myString = </span><span style='color: #a31515; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>"some
value"</span> you are actually creating an object, which is tracked by the garbage collector. This is a nifty feature as you don't have to free() the string after use. However, it is a double-edged sword when it comes to security. The string might be kept in memory for a <a href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#what-happens-during-a-garbage-collection" rel="noopener noreferrer" target="_blank">very long time,</a> even after it has been used and is not required anymore.</div>
<div>
<br/></div>
<div>
In the example above with S3, if a malicious actor has the ability to look into your application memory, then he will get hold of the secret access key, and therefore direct access to download files from your S3 bucket. This is a reoccurring issue for websites that utilize cloud services in the backend, as access is governed by access control (access keys) alone.</div>
<div>
<br/></div>
<div>
Security bugs that result in remote information disclosure are misused by attackers on a daily basis, and sometimes a bug like <a href="http://heartbleed.com/" rel="noopener noreferrer" target="_blank">HeartBleed</a> is discovered, that when attackers exploit it, millions of applications are suddenly vulnerable to remote memory disclosure.</div>
<div>
<br/></div>
<div>
Languages like Java, C#, VB.net and Go all have a garbage collector, so the issue described in this section pertains to applications written in any of them.</div>
<h2>
It Gets Worse...</h2>
<div>
The quick-thinking developer might say: "<i>Just overwrite the string with another value to clear the secret from memory!</i>"</div>
<div>
<br/></div>
<div>
<div class="MsoNormal">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>string</span><span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'> myString = </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>null</span><span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>;</span><o:p></o:p></div>
</div>
<div>
<br/></div>
<div>
A fallacious thought, which does not work.</div>
<div>
<br/></div>
<div>
In C#, not only are strings garbage collected, but they are also <a href="https://en.wikipedia.org/wiki/String_interning" rel="noopener noreferrer" target="_blank">interned</a>. String Interning is great for performance and reducing memory usage, but it is a nightmare for security. In order to intern strings, you have to design the string as an <a href="https://en.wikipedia.org/wiki/Immutable_object" rel="noopener noreferrer" target="_blank">immutable object</a>. This means that when you assign your string to something else, it actually stores the original object and creates a new one - and therefore the value is not overwritten.</div>
<div>
<br/></div>
<div>
Since the interned string pool contains references to unique strings in your application, setting a string to null would create havoc everywhere else in your application the string is used, so it simply sits there until your application closes down.</div>
<h2>
... Before it Gets Better</h2>
<div>
So what should we do?</div>
<div>
<br/></div>
<div>
That's simple: <b>never use strings for secrets</b>. At least not in garbage collected and string interned programming languages.</div>
<div>
<br/></div>
<div>
I've seen many different solutions to the problem. Everything from pinning the value in memory an overwriting it using unmanaged code to scanning the process memory for the string and nuking it. While some of them might work, it is a lot of hacks and workarounds to a problem that shouldn't exist in the first place.</div>
<div>
<br/></div>
<div>
Simply do not use strings for secrets, and instead utilize the right tools for the right job. .NET already has 2 solutions to help us out:</div>
<div>
<br/></div>
<div>
- <a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netframework-4.8" rel="noopener noreferrer" target="_blank">SecureString</a></div>
<div>
- <a href="https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction?view=aspnetcore-2.2" rel="noopener noreferrer" target="_blank">Data Protection framework</a></div>
<div>
<br/></div>
<div>
I have not added AES encryption to the list as you should rely on existing robust data protection frameworks instead. I'll go into detail on each solution below.</div>
<h2>
SecureString</h2>
<div>
SecureString is the most underutilized feature of .NET. It can provide in-memory encryption of your application secrets, but unfortunately, only provide low-level functionality, and is therefore hard to use alone. Here is how you securely create a SecureString:</div>
<div>
<br/></div>
<div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>byte</span><span style='font-family: "consolas"; font-size: 9.5pt;'>[] key = { 115, 101, 99, 114, 101, 116 }; </span><span style='color: green; font-family: "consolas"; font-size: 9.5pt;'>//"secret"</span><span style='font-family: "consolas"; font-size: 9.5pt;'><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<br/></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>SecureString
secure = </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>new</span><span style='font-family: "consolas"; font-size: 9.5pt;'> SecureString();<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<br/></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>foreach</span><span style='font-family: "consolas"; font-size: 9.5pt;'> (</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>byte</span><span style='font-family: "consolas"; font-size: 9.5pt;'> b </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>in</span><span style='font-family: "consolas"; font-size: 9.5pt;'> key)<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>{<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    secure.AppendChar((</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>char</span><span style='font-family: "consolas"; font-size: 9.5pt;'>)b);<o:p></o:p></span></div>
<div class="MsoNormal">
<span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>}</span><o:p></o:p></div>
<div class="MsoNormal">
<span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'><br/></span></div>
<div class="MsoNormal">
<span style="font-size: 12.6667px; line-height: 107%;"><span style='font-family: "consolas";'>secure.MakeReadOnly();</span></span></div>
<div class="MsoNormal">
<span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'></span></div>
<div class="MsoNormal">
<span style='font-family: "consolas";'><span style="font-size: 12.6667px;">Array.Clear(key, 0, key.Length);</span></span></div>
</div>
<div>
<br/></div>
<div>
No strings in sight! Instead, we use a byte array with the content "secret" instead. Since byte arrays are reference types, they are garbage collected and we have to clear the content after use. They are not interned like strings, so we don't have to worry about any side-effects of clearing it.</div>
<div>
<br/></div>
<div>
The call to MakeReadOnly() ensures the SecureString can't be written to after the initialization - another small security perk we get for free.</div>
<div>
<br/></div>
<div>
The question is: how do we read the content of SecureString? well... you don't - or rather - you can't. At least not without writing some code yourself. SecureString has a strict design that ensures you can't mess up. If they provided a way for you to get a string from a SecureString, then we would be back to where we started. However, we can do something like:</div>
<div>
<br/></div>
<div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>private</span><span style='font-family: "consolas"; font-size: 9.5pt;'> IEnumerable&lt;</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>char</span><span style='font-family: "consolas"; font-size: 9.5pt;'>&gt; ReadSecureString(SecureString secure)<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>{<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    IntPtr ptr = IntPtr.Zero;<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>try</span><span style='font-family: "consolas"; font-size: 9.5pt;'><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    {<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>        ptr =
Marshal.SecureStringToGlobalAllocUnicode(secure);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>        </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>for</span><span style='font-family: "consolas"; font-size: 9.5pt;'> (</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>int</span><span style='font-family: "consolas"; font-size: 9.5pt;'> i = 0; i
&lt; secure.Length; i++)<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>        {<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>            </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>yield</span><span style='font-family: "consolas"; font-size: 9.5pt;'> </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>return</span><span style='font-family: "consolas"; font-size: 9.5pt;'> (</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>char</span><span style='font-family: "consolas"; font-size: 9.5pt;'>)Marshal.ReadInt16(ptr, i * 2);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>        }<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    }<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    </span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>finally</span><span style='font-family: "consolas"; font-size: 9.5pt;'><o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    {<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>       
Marshal.ZeroFreeGlobalAllocUnicode(ptr);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas"; font-size: 9.5pt;'>    }<o:p></o:p></span></div>
<div class="MsoNormal">
<span style='font-family: "consolas"; font-size: 9.5pt; line-height: 107%;'>}</span><o:p></o:p></div>
</div>
<div>
<br/></div>
<div>
Since we are still not using a string we are still good.</div>
<div>
<br/></div>
<div>
Under the hood of SecureString, the data we gave it is encrypted using Microsoft Windows Data Protection API (DPAPI). When running in a users context, the key used is based on the user's login password, so the attacker would need to know that password in order to decrypt the secret.</div>
<h2>
The Data Protection framework</h2>
<div>
Microsoft also provides a NuGet package called <a href="https://www.nuget.org/packages/Microsoft.AspNetCore.DataProtection/">Microsoft.AspNetCore.DataProtection</a>. Don't let the AspNetCore section of the name fool you; it can be used by any type of application, not just ASP.NET Core.</div>
<div>
<br/></div>
<div>
With this framework, you get the ability to protect and unprotect blobs of data, and much like SecureString above, we can also <a href="https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-encryption-at-rest?view=aspnetcore-2.2#windows-dpapi">use DPAPI</a> as part of the encryption process. However, in this example, I'm going to use plain old key files instead.</div>
<div>
<br/></div>
<div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>byte</span><span style='font-family: "consolas"; font-size: 9.5pt;'>[] key = { 115, 101, 99, 114, 101, 116 }; </span><span style='color: green; font-family: "consolas"; font-size: 9.5pt;'>//"secret"</span></div>
<div>
<br/></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>IDataProtectionProvider
dpp = DataProtectionProvider.Create(</span><span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>new</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'> DirectoryInfo(</span><span style='color: maroon; font-family: "consolas"; font-size: 9.5pt;'>@"C:\Keys\"</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>));<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>IDataProtector
protector = dpp.CreateProtector(</span><span style='color: #a31515; font-family: "consolas"; font-size: 9.5pt;'>"SecretsProtector"</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'><br/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>byte</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>[] encrypted = protector.Protect(key);<o:p></o:p></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='font-family: "consolas";'><span style="font-size: 12.6667px;">Array.Clear(key, 0, key.Length);</span></span></div>
<div>
<br/></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0in; mso-layout-grid-align: none; text-autospace: none;">
<span style='color: blue; font-family: "consolas"; font-size: 9.5pt;'>byte</span><span style='color: black; font-family: "consolas"; font-size: 9.5pt;'>[] notEncrypted = protector.Unprotect(encrypted);<o:p></o:p></span><br/>
<span style='color: black; font-family: "consolas"; font-size: 9.5pt;'><br/></span></div>
</div>
<div>
the Data Protection framework generates a key file and puts it into C:\Keys\, it then uses that key file to encrypt our key, which can then decrypt using the same protector. Since we are not using strings and we are clearing the original key after encryption, we have followed best practices.<br/>
<br/>
Microsoft's Data Protection framework has a ton of nice features, including rotating keys, encryption usage compliance (like FIPS), Azure Key Vault storage and many more. Instead of trying to build your own secure storage based on AES, use something like Data Protection as a foundation.</div>
<h2>
SecureString vs. Data Protection</h2>
<div>
So when should we use one over the other? That's a hard question, and it really comes down to your requirements, but I can provide some examples from my own experience.</div>
<div>
<br/></div>
<div>
Use SecureString when...</div>
<div>
- You are building a library and you want to guarantee your code is secure</div>
<div>
- You don't require persistent storage of the secret in a secure format</div>
<div>
- You don't need to transmit the secret to someone else</div>
<div>
<br/>
<b>Update 2019-08-04</b>: Microsoft has deprecated SecureString as it does not work across platforms. See the remark in <a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netframework-4.8" rel="noopener noreferrer" target="_blank">the documentation</a>.<br/>
<br/></div>
<div>
Use Data Protection when...</div>
<div>
- You are in full control of the application</div>
<div>
- You need to store or transmit the encryption keys</div>
<div>
- You need to ensure you follow compliance standards such as FIPS</div>
<div>
<br/></div>
<div>
SecureString is really just a primitive data type while Data Protection is a full framework, so in most cases you would probably want to utilize Data Protection for storing secrets securely at-rest (such as an encrypted config file), and then get a value from that config file as a SecureString in order to send it to a third-party library. Be sure to use the right tool for the right job.</div>
<h2>
But... [LibraryNameHere] Requires a String</h2>
<div>
Yep, and that's the case with almost all libraries, including Amazons own S3 client we used as an example in the beginning. They just don't know how to do it securely, so send them a link to this article.</div>
<div>
<br/></div>
<div>
The target here is to ensure we only keep the secrets in memory when needed, but always have a way to get the original secrets if/when needed - just <b>not</b> as a string.</div>
<div>
<br/></div>
<div>
If a library requires a secret key as a string, then you have no choice. You have to give it a string. But please do your part and report it back to the developer.</div>]]></content><author><name>Ian Qvist</name></author><category term="Security" /><category term="Security" /><summary type="html"><![CDATA[There are times when you have to store secrets in your application. You wish to do it securely, but how exactly would you do that? It is more problematic than you think, and if you don't design your application around certain concepts, you will end up with a security nightmare that is nearly impossible to solve. Let's take a look at an example. Here we are using the popular S3 client from Amazon's official AWS SDK for .NET: AWSCredentials cred = new BasicAWSCredentials("keyId", "secretAccessKey"); using (AmazonS3Client client = new AmazonS3Client(cred)) {     //do something with client } The problem here is that you are forced to enter the secret access key as a string, and strings are not designed around security best practices. In .NET, strings are garbage collected, in contrast to integers, DateTime and other data types, which are not garbage collected. It is not the only problem with strings, but let's take one issue at the time. Strings are Garbage (Collected) When you initialize a string like string myString = "some value" you are actually creating an object, which is tracked by the garbage collector. This is a nifty feature as you don't have to free() the string after use. However, it is a double-edged sword when it comes to security. The string might be kept in memory for a very long time, even after it has been used and is not required anymore. In the example above with S3, if a malicious actor has the ability to look into your application memory, then he will get hold of the secret access key, and therefore direct access to download files from your S3 bucket. This is a reoccurring issue for websites that utilize cloud services in the backend, as access is governed by access control (access keys) alone. Security bugs that result in remote information disclosure are misused by attackers on a daily basis, and sometimes a bug like HeartBleed is discovered, that when attackers exploit it, millions of applications are suddenly vulnerable to remote memory disclosure. Languages like Java, C#, VB.net and Go all have a garbage collector, so the issue described in this section pertains to applications written in any of them. It Gets Worse... The quick-thinking developer might say: "Just overwrite the string with another value to clear the secret from memory!" string myString = null; A fallacious thought, which does not work. In C#, not only are strings garbage collected, but they are also interned. String Interning is great for performance and reducing memory usage, but it is a nightmare for security. In order to intern strings, you have to design the string as an immutable object. This means that when you assign your string to something else, it actually stores the original object and creates a new one - and therefore the value is not overwritten. Since the interned string pool contains references to unique strings in your application, setting a string to null would create havoc everywhere else in your application the string is used, so it simply sits there until your application closes down. ... Before it Gets Better So what should we do? That's simple: never use strings for secrets. At least not in garbage collected and string interned programming languages. I've seen many different solutions to the problem. Everything from pinning the value in memory an overwriting it using unmanaged code to scanning the process memory for the string and nuking it. While some of them might work, it is a lot of hacks and workarounds to a problem that shouldn't exist in the first place. Simply do not use strings for secrets, and instead utilize the right tools for the right job. .NET already has 2 solutions to help us out: - SecureString - Data Protection framework I have not added AES encryption to the list as you should rely on existing robust data protection frameworks instead. I'll go into detail on each solution below. SecureString SecureString is the most underutilized feature of .NET. It can provide in-memory encryption of your application secrets, but unfortunately, only provide low-level functionality, and is therefore hard to use alone. Here is how you securely create a SecureString: byte[] key = { 115, 101, 99, 114, 101, 116 }; //"secret" SecureString secure = new SecureString(); foreach (byte b in key) {     secure.AppendChar((char)b); } secure.MakeReadOnly(); Array.Clear(key, 0, key.Length); No strings in sight! Instead, we use a byte array with the content "secret" instead. Since byte arrays are reference types, they are garbage collected and we have to clear the content after use. They are not interned like strings, so we don't have to worry about any side-effects of clearing it. The call to MakeReadOnly() ensures the SecureString can't be written to after the initialization - another small security perk we get for free. The question is: how do we read the content of SecureString? well... you don't - or rather - you can't. At least not without writing some code yourself. SecureString has a strict design that ensures you can't mess up. If they provided a way for you to get a string from a SecureString, then we would be back to where we started. However, we can do something like: private IEnumerable&lt;char&gt; ReadSecureString(SecureString secure) {     IntPtr ptr = IntPtr.Zero;     try     {         ptr = Marshal.SecureStringToGlobalAllocUnicode(secure);         for (int i = 0; i &lt; secure.Length; i++)         {             yield return (char)Marshal.ReadInt16(ptr, i * 2);         }     }     finally     {         Marshal.ZeroFreeGlobalAllocUnicode(ptr);     } } Since we are still not using a string we are still good. Under the hood of SecureString, the data we gave it is encrypted using Microsoft Windows Data Protection API (DPAPI). When running in a users context, the key used is based on the user's login password, so the attacker would need to know that password in order to decrypt the secret. The Data Protection framework Microsoft also provides a NuGet package called Microsoft.AspNetCore.DataProtection. Don't let the AspNetCore section of the name fool you; it can be used by any type of application, not just ASP.NET Core. With this framework, you get the ability to protect and unprotect blobs of data, and much like SecureString above, we can also use DPAPI as part of the encryption process. However, in this example, I'm going to use plain old key files instead. byte[] key = { 115, 101, 99, 114, 101, 116 }; //"secret" IDataProtectionProvider dpp = DataProtectionProvider.Create(new DirectoryInfo(@"C:\Keys\")); IDataProtector protector = dpp.CreateProtector("SecretsProtector"); byte[] encrypted = protector.Protect(key); Array.Clear(key, 0, key.Length); byte[] notEncrypted = protector.Unprotect(encrypted); the Data Protection framework generates a key file and puts it into C:\Keys\, it then uses that key file to encrypt our key, which can then decrypt using the same protector. Since we are not using strings and we are clearing the original key after encryption, we have followed best practices. Microsoft's Data Protection framework has a ton of nice features, including rotating keys, encryption usage compliance (like FIPS), Azure Key Vault storage and many more. Instead of trying to build your own secure storage based on AES, use something like Data Protection as a foundation. SecureString vs. Data Protection So when should we use one over the other? That's a hard question, and it really comes down to your requirements, but I can provide some examples from my own experience. Use SecureString when... - You are building a library and you want to guarantee your code is secure - You don't require persistent storage of the secret in a secure format - You don't need to transmit the secret to someone else Update 2019-08-04: Microsoft has deprecated SecureString as it does not work across platforms. See the remark in the documentation. Use Data Protection when... - You are in full control of the application - You need to store or transmit the encryption keys - You need to ensure you follow compliance standards such as FIPS SecureString is really just a primitive data type while Data Protection is a full framework, so in most cases you would probably want to utilize Data Protection for storing secrets securely at-rest (such as an encrypted config file), and then get a value from that config file as a SecureString in order to send it to a third-party library. Be sure to use the right tool for the right job. But... [LibraryNameHere] Requires a String Yep, and that's the case with almost all libraries, including Amazons own S3 client we used as an example in the beginning. They just don't know how to do it securely, so send them a link to this article. The target here is to ensure we only keep the secrets in memory when needed, but always have a way to get the original secrets if/when needed - just not as a string. If a library requires a secret key as a string, then you have no choice. You have to give it a string. But please do your part and report it back to the developer.]]></summary></entry><entry><title type="html">FindDupes 1.1 released</title><link href="https://genbox.github.io/2019/05/finddupes-11-released.html" rel="alternate" type="text/html" title="FindDupes 1.1 released" /><published>2019-05-18T18:05:00+00:00</published><updated>2019-05-18T18:05:25+00:00</updated><id>https://genbox.github.io/2019/05/finddupes-11-released</id><content type="html" xml:base="https://genbox.github.io/2019/05/finddupes-11-released.html"><![CDATA[I've released a new version of FindDupes. It now groups files by size before hashing, thereby dramatically speeding up the deduplication process.<br/>
If you have .NET Core installed, you can install the tool by running:<br/>
<br/>
<pre style='background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;'>dotnet tool install <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">--</span>global FindDupes</pre>
<br/>
If you want to look through the code or report any issues, head over to <a href="https://github.com/Genbox/FindDupes">https://github.com/Genbox/FindDupes</a>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[I've released a new version of FindDupes. It now groups files by size before hashing, thereby dramatically speeding up the deduplication process. If you have .NET Core installed, you can install the tool by running: dotnet tool install --global FindDupes If you want to look through the code or report any issues, head over to https://github.com/Genbox/FindDupes]]></summary></entry><entry><title type="html">Beware of BrotliStream in .NET Core 2.1</title><link href="https://genbox.github.io/2018/05/beware-of-brotlistream-in-net-core-21.html" rel="alternate" type="text/html" title="Beware of BrotliStream in .NET Core 2.1" /><published>2018-05-12T21:35:00+00:00</published><updated>2022-09-04T09:11:35+00:00</updated><id>https://genbox.github.io/2018/05/beware-of-brotlistream-in-net-core-21</id><content type="html" xml:base="https://genbox.github.io/2018/05/beware-of-brotlistream-in-net-core-21.html"><![CDATA[I love compression algorithms and have built a fair share of my own for fun and profit. It is a difficult task to build something that is efficient when it comes to the compromise between speed and compression ratio, so when I saw Google's Brotli algorithm mentioned in the <a href="https://blogs.msdn.microsoft.com/dotnet/2018/05/07/announcing-net-core-2-1-rc-1/" rel="noopener noreferrer" target="_blank">.NET Core 2.1 RC1 announcement</a>, I was estatic!<div>
<br/></div>
<div>
It lasted about 15 minutes until I put the BrotliStream to a test, only to find out that it took 140x longer to compress a 518 MB file!</div>
<div>
<br/></div>
<div>
Curious if this was a bug, I delved into the code and realized that the default compression level <a href="https://github.com/dotnet/corefx/blob/8f9cfa462dfc2ec5bdbbe2462693036861fb0199/src/System.IO.Compression.Brotli/src/System/IO/Compression/BrotliUtils.cs#L13" rel="noopener noreferrer" target="_blank">is set to 11</a>. For those not familiar with Brotli, that is the highest level available, that prioritize compression ratio above speed.</div>
<div>
<br/></div>
<div>
I <a href="https://github.com/dotnet/corefx/issues/29555" rel="noopener noreferrer" target="_blank">reported it as an issue</a>, but Microsoft seems to think that having the same configuration as Google's Brotli library is more important than a sane default, so it is only a matter of time before tons of StackOverflow posts popup complaining about the speed of BrotliStream.</div>
<div>
<br/></div>
<div>
If you want to use Brotli in your application (a wise choice! it is a good algorithm), be sure to NOT use the builtin CompressionLevel enum in the BrotliStream constructor. Instead, cast an integer (I would recommend a value of 6) like this:</div>
<div>
<br/></div>
<div>
BrotliStream stream = new BrotliStream(sm, (CompressionLevel)6);</div>
<div>
<br/></div>
<div>
That is a good compromise between speed and compression ratio for most data.</div><div><br/></div><div>Update 2021-11-01: Microsoft decided to block user settings <a href="https://github.com/dotnet/runtime/pull/57561">in this merge request</a>.</div><div><br/></div><div>Update 2022-05-01: Microsoft now <a href="https://github.com/dotnet/runtime/pull/72266">defaults to quality 4</a>. It will be part of .NET 7.</div><div><br/></div><div>Update 2022-09-01: <a href="https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#compression" rel="noopener noreferrer" target="_blank">Microsoft acknowledges the problem</a>, but stays with the decision of setting quality to 4.</div>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[I love compression algorithms and have built a fair share of my own for fun and profit. It is a difficult task to build something that is efficient when it comes to the compromise between speed and compression ratio, so when I saw Google's Brotli algorithm mentioned in the .NET Core 2.1 RC1 announcement, I was estatic! It lasted about 15 minutes until I put the BrotliStream to a test, only to find out that it took 140x longer to compress a 518 MB file! Curious if this was a bug, I delved into the code and realized that the default compression level is set to 11. For those not familiar with Brotli, that is the highest level available, that prioritize compression ratio above speed. I reported it as an issue, but Microsoft seems to think that having the same configuration as Google's Brotli library is more important than a sane default, so it is only a matter of time before tons of StackOverflow posts popup complaining about the speed of BrotliStream. If you want to use Brotli in your application (a wise choice! it is a good algorithm), be sure to NOT use the builtin CompressionLevel enum in the BrotliStream constructor. Instead, cast an integer (I would recommend a value of 6) like this: BrotliStream stream = new BrotliStream(sm, (CompressionLevel)6); That is a good compromise between speed and compression ratio for most data.Update 2021-11-01: Microsoft decided to block user settings in this merge request.Update 2022-05-01: Microsoft now defaults to quality 4. It will be part of .NET 7.Update 2022-09-01: Microsoft acknowledges the problem, but stays with the decision of setting quality to 4.]]></summary></entry><entry><title type="html">Performance Measurement Mistakes in Academic Publications</title><link href="https://genbox.github.io/2018/01/performance-measurement-mistakes-in.html" rel="alternate" type="text/html" title="Performance Measurement Mistakes in Academic Publications" /><published>2018-01-07T16:02:00+00:00</published><updated>2018-01-07T16:06:47+00:00</updated><id>https://genbox.github.io/2018/01/performance-measurement-mistakes-in</id><content type="html" xml:base="https://genbox.github.io/2018/01/performance-measurement-mistakes-in.html"><![CDATA[One of the fastest ways to get me to stop reading a paper is to make incorrect assumptions in the hypothesis or rely on previous work that is not completely solid. There is no doubt that research in the academic context is hard, and writing a paper about it is even harder, but the value of all this hard work is diminished if you make a mistake.<br/>
<br/>
This time, I will focus on performance measurement mistakes in computer science papers. They come in different flavours and are sometimes very subtle. Performance is paramount in algorithmics and some researchers don't do their due diligence when trying to prove theirs is faster. Here are the 3 most often occurring mistakes I see, in no particular order.<br/>
<h2>
Performance Measurements on Different Hardware</h2>
<div>
When measuring performance, it is paramount to do it under the right circumstances. Every so often I come across a paper that states algorithm X is 4x faster than algorithm Y, but they measured it using absolute numbers between two very different hardware configurations. Of curse, if algorithm X takes 10 ms to run, and Y takes 20 ms to run <b>on the same hardware</b>, it might be faster. I see this problem occurring a lot in the fields of cryptocurrency (GPU acceleration) or Machine Learning (GPU/TPU acceleration).</div>
<div>
<br/></div>
<div>
Researchers should use asymptotic notation - also called Big O notation - to indicate the algorithmic complexity of their algorithm. If your algorithm is asymptotically slower than another, such as O(n^2) vs. O(n), then it is up to you to demonstrate under which conditions your algorithm is actually faster. Whether it be parallelization, specialization on specific architectures or even favoured by certain compiler optimizations, it is your responsibility to make sure it is illuminated by the paper.</div>
<div>
<br/></div>
<div>
If you want to demonstrate any of those specialized cases, you are measuring efficiency, which is measured in cycles pr. operation. Calculate how fast your algorithm performs compared to others in that and you will be much better off.</div>
<h2>
Parallelization as an Excuse for Speed</h2>
<div>
Today, CPUs are no longer getting faster, they are just getting more cores. Since all previous work in computer science was centred around single core execution, no care was taken to parallelization. Researchers today take advantage of the many cores in computers, which often leads them to make the mistake of assuming that parallelization means more speed.</div>
<div>
<br/></div>
<div>
Speed is not the same as throughput. When we measure an algorithm, we measure the efficiency of the execution of some data. The fact that you can do it on two cores at the same time might double your throughput, but shows nothing about efficiency or speed. I often see the same mistake when measuring network bandwidth. For example:</div>
<div>
<br/></div>
<div>
You have a 100 megabit/second network connection. That means 100.000.000 bits can flow through your network card per second, and therefore your throughput is 100 megabits/second.</div>
<div>
<br/></div>
<div>
However, in order for that to make sense, you need to send it somewhere. How fast your network card can send the data out is the speed. Let's say you send 3 packets of 5 bits each, and it takes 1 milliseconds between each packet:</div>
<div>
<br/></div>
<div>
[data].[data].[data]</div>
<div>
<br/></div>
<div>
Your throughput/bandwidth is now said to be 5 bits/ms, and the speed is also 5 bits/ms. You decide to add another network card so you can send data in parallel:</div>
<div>
<br/></div>
<div>
[data].[data].[data]</div>
<div>
[data].[data].[data]</div>
<div>
<br/></div>
<div>
You just doubled your bandwidth, but speed is still 5 bit/ms!</div>
<div>
<br/></div>
<div>
In this analogy, network cards are CPU cores. Measuring the speed of your algorithm by doubling the number of CPU cores you use makes no sense. It is a lot better if you illustrate the fact that your algorithm is parallelizable compared to others, but don't try to put some data into it and say that your algorithm is faster because it did the job in 50% of the time.</div>
<h2>
Reduction of Asymptotic Notation</h2>
<div>
I've read papers that state their algorithms are constant (O(1)) in running time. Their argument is that they split the problem into a smaller set of problems, and each problem takes 1/n to solve, and therefore the same as O(1).</div>
<div>
<br/></div>
<div>
No. That is not how it works.</div>
<div>
<br/></div>
<div>
Algorithmic complexity does not change with data. It only changes if you change the algorithm. Data has nothing to do with the algorithm's complexity.</div>
<div>
<br/></div>
<div>
What you are really measuring is the algorithms ability to solve a particular problem, and even then you can't say your algorithm is faster because of less data. You can't speed up a sorting algorithm by running it on smaller chunks of data and claim it to be O(1). A sorting algorithm can never be below O(n) running time as you have to compare to all elements.</div>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[One of the fastest ways to get me to stop reading a paper is to make incorrect assumptions in the hypothesis or rely on previous work that is not completely solid. There is no doubt that research in the academic context is hard, and writing a paper about it is even harder, but the value of all this hard work is diminished if you make a mistake. This time, I will focus on performance measurement mistakes in computer science papers. They come in different flavours and are sometimes very subtle. Performance is paramount in algorithmics and some researchers don't do their due diligence when trying to prove theirs is faster. Here are the 3 most often occurring mistakes I see, in no particular order. Performance Measurements on Different Hardware When measuring performance, it is paramount to do it under the right circumstances. Every so often I come across a paper that states algorithm X is 4x faster than algorithm Y, but they measured it using absolute numbers between two very different hardware configurations. Of curse, if algorithm X takes 10 ms to run, and Y takes 20 ms to run on the same hardware, it might be faster. I see this problem occurring a lot in the fields of cryptocurrency (GPU acceleration) or Machine Learning (GPU/TPU acceleration). Researchers should use asymptotic notation - also called Big O notation - to indicate the algorithmic complexity of their algorithm. If your algorithm is asymptotically slower than another, such as O(n^2) vs. O(n), then it is up to you to demonstrate under which conditions your algorithm is actually faster. Whether it be parallelization, specialization on specific architectures or even favoured by certain compiler optimizations, it is your responsibility to make sure it is illuminated by the paper. If you want to demonstrate any of those specialized cases, you are measuring efficiency, which is measured in cycles pr. operation. Calculate how fast your algorithm performs compared to others in that and you will be much better off. Parallelization as an Excuse for Speed Today, CPUs are no longer getting faster, they are just getting more cores. Since all previous work in computer science was centred around single core execution, no care was taken to parallelization. Researchers today take advantage of the many cores in computers, which often leads them to make the mistake of assuming that parallelization means more speed. Speed is not the same as throughput. When we measure an algorithm, we measure the efficiency of the execution of some data. The fact that you can do it on two cores at the same time might double your throughput, but shows nothing about efficiency or speed. I often see the same mistake when measuring network bandwidth. For example: You have a 100 megabit/second network connection. That means 100.000.000 bits can flow through your network card per second, and therefore your throughput is 100 megabits/second. However, in order for that to make sense, you need to send it somewhere. How fast your network card can send the data out is the speed. Let's say you send 3 packets of 5 bits each, and it takes 1 milliseconds between each packet: [data].[data].[data] Your throughput/bandwidth is now said to be 5 bits/ms, and the speed is also 5 bits/ms. You decide to add another network card so you can send data in parallel: [data].[data].[data] [data].[data].[data] You just doubled your bandwidth, but speed is still 5 bit/ms! In this analogy, network cards are CPU cores. Measuring the speed of your algorithm by doubling the number of CPU cores you use makes no sense. It is a lot better if you illustrate the fact that your algorithm is parallelizable compared to others, but don't try to put some data into it and say that your algorithm is faster because it did the job in 50% of the time. Reduction of Asymptotic Notation I've read papers that state their algorithms are constant (O(1)) in running time. Their argument is that they split the problem into a smaller set of problems, and each problem takes 1/n to solve, and therefore the same as O(1). No. That is not how it works. Algorithmic complexity does not change with data. It only changes if you change the algorithm. Data has nothing to do with the algorithm's complexity. What you are really measuring is the algorithms ability to solve a particular problem, and even then you can't say your algorithm is faster because of less data. You can't speed up a sorting algorithm by running it on smaller chunks of data and claim it to be O(1). A sorting algorithm can never be below O(n) running time as you have to compare to all elements.]]></summary></entry><entry><title type="html">Reducing the size of self-contained .NET Core applications</title><link href="https://genbox.github.io/2018/01/reducing-size-of-self-contained-net.html" rel="alternate" type="text/html" title="Reducing the size of self-contained .NET Core applications" /><published>2018-01-01T17:47:00+00:00</published><updated>2018-01-01T18:08:19+00:00</updated><id>https://genbox.github.io/2018/01/reducing-size-of-self-contained-net</id><content type="html" xml:base="https://genbox.github.io/2018/01/reducing-size-of-self-contained-net.html"><![CDATA[Just for note keeping, I've written down some methods of reducing the size of a .NET Core application. I thought others could use it as well, so here you go.<br/>
<h2>
Original Size</h2>
First off, let's see how much disk space a <a href="https://docs.microsoft.com/en-us/dotnet/core/deploying/" rel="noopener noreferrer" target="_blank">self-contained</a> 'hello world' application takes up.<br/>
<br/>
&gt; dotnet new console<br/>
&gt; dotnet publish -r win-x86 -c release<br/>
<br/>
Size: 53.9 MB - <b>yuck!</b><br/>
<h2>
Trimming</h2>
<div>
Microsoft has built <a href="https://github.com/dotnet/standard/blob/master/Microsoft.Packaging.Tools.Trimming/docs/trimming.md" rel="noopener noreferrer" target="_blank">a tool</a> that finds unused assemblies and removes them from the distribution package. This is much needed since the 'netcoreapp2.0' profile is basically .NET Framework all over again, and it contains a truckload of assemblies our little 'hello world' application don't use.</div>
<div>
<br/></div>
<div>
&gt; dotnet new console</div>
<div>
&gt; dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.0-preview1-25818-01</div>
<div>
&gt; dotnet publish -r win-x86 -c release /p:TrimUnusedDependencies=true</div>
<div>
<br/></div>
<div>
Size: 15.8 MB</div>
<div>
<br/></div>
<div>
Much better! Although, we have only removed unused assemblies - what about unused code?</div>
<h2>
Linking</h2>
<div>
The Mono team over at Xamarin has <a href="https://github.com/dotnet/core/blob/master/samples/linker-instructions.md" rel="noopener noreferrer" target="_blank">built a linker</a> that can remove unused code from assemblies. If you only use List&lt;T&gt; from System.Collections.Generic.dll, why have HashSet&lt;T&gt; and all the other classes? This has a huge impact reflection obviously, so use with care.</div>
<div>
<br/></div>
<div>
&gt; dotnet new console</div>
<div>
&gt; dotnet new nuget<br/>
<br/></div>
<div>
Open nuget.config and add &lt;add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /&gt;<br/>
<br/></div>
<div>
&gt; dotnet add package ILLink.Tasks -v 0.1.4-preview-981901</div>
<div>
&gt; dotnet publish -r win-x86 -c release</div>
<div>
<br/></div>
<div>
Size: 22.9 MB</div>
<div>
<br/></div>
<div>
Not as good as trimming it seems, but definitely better than doing nothing.</div>
<h2>
.NET Native</h2>
<div>
In the world of C, we have a thing called 'static linking' which means all assemblies get linked into a single assembly. This is very nice for small applications or deployments that can't rely on existing assemblies on the system. C# does not have this feature, but with .NET Native we get something very close.</div>
<div>
<br/></div>
<div>
.NET Native is actually a refactored runtime called CoreRT, which uses RyuJIT to create native assemblies. Getting it to work is <a href="https://github.com/dotnet/corert/blob/master/Documentation/how-to-build-and-run-ilcompiler-in-console-shell-prompt.md" rel="noopener noreferrer" target="_blank">not as easy</a> as trimming or linking since unfortunately Microsoft only supports UWP as a native platform. .NET Core is therefore left out in the cold for now.<br/>
<br/></div>
<div>
</div>
<div>
1. Download <a href="https://cmake.org/download/" rel="noopener noreferrer" target="_blank">CMake</a> 3.8 or later. I choose <a href="https://cmake.org/files/v3.10/cmake-3.10.1-win64-x64.msi">cmake-3.10.1-win64-x64.msi</a></div>
<div>
2. Make sure you have Visual Studio 2017 with C++ support installed</div>
<div>
3. Download the latest successful build. Check <a href="https://ci.dot.net/job/dotnet_corert/job/master/job/debug_windows_nt/lastStableBuild/" rel="noopener noreferrer" target="_blank">their Jenkins</a> for commit hash.</div>
<div>
4. Unpack the content to c:\corert\</div>
<div>
5. Open 'x64 Native Tools Command Prompt for VS 2017'</div>
<div>
6. Now you should compile .NET Native:</div>
<div>
<br/></div>
&gt; cd c:\corert<br/>
&gt; build.bat release<br/>
<div>
<br/></div>
<div>
Note that it takes a long time to download missing packages and compile the whole project.</div>
<div>
<br/></div>
<div>
7. Create a new .NET Core project and add .NET Native msbuild targets:</div>
<div>
<br/></div>
<div>
&gt; mkdir c:\test</div>
<div>
&gt; cd c:\test</div>
<div>
&gt; dotnet new console</div>
<div>
&gt; set IlcPath=c:\corert\bin\Windows_NT.x64.Release</div>
<div>
<br/></div>
<div>
8. edit test.csproj and add the two lines just before '&lt;/Project&gt;':<br/>
<br/>
&lt;Import Project="$(MSBuildSDKsPath)\Microsoft.NET.Sdk\Sdk\Sdk.targets" /&gt;<br/>
<div>
&lt;Import Project="$(IlcPath)\build\Microsoft.NETCore.Native.targets" /&gt;</div>
</div>
<div>
<br/></div>
<div>
&gt; dotnet publish -r win-x64 -c release</div>
<div>
<br/></div>
<div>
Size: 3.95 MB</div>
<div>
<br/></div>
<div>
Wow! Unused assembles and unused code has been removed and everything is statically compiled into an executable. Note that I used x64 and not x86 in the .NET Native build, as I'm not sure .NET Native supports x86 fully yet.</div>
<h2>
Bonus: Trim and Link</h2>
<div>
We can actually use both trimming and linking to reduce the size of the application further. It seems that the trimmer is better at finding unused assemblies than the linker is, but if we do both steps, the trimmer will remove assemblies and the linker will remove the dead code from the remaining assemblies.</div>
<div>
<br/></div>
<div>
Just add both steps together like this:</div>
<div>
<br/></div>
<div>
<div>
&gt; dotnet new console</div>
<div>
&gt; dotnet new nuget</div>
<div>
<br/>
Open nuget.config and add &lt;add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /&gt;</div>
<div>
<br/>
&gt; dotnet add package ILLink.Tasks -v 0.1.4-preview-981901</div>
<div>
<div>
&gt; dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.0-preview1-25818-01</div>
<div>
&gt; dotnet publish -r win-x86 -c release /p:TrimUnusedDependencies=true</div>
</div>
</div>
<div>
<br/></div>
<div>
Size: 14.9 MB</div>
<div>
<br/></div>
<div>
Final size is pretty much as low as it gets right now without native compilation.<br/>
<h2>
Conclusion</h2>
</div>
<div>
We can easily reduce the size of self-contained .NET Core application, we just have to add the right packages and switches. Microsoft has changed the behaviour of the .NET Core project and publish system several times now, which has made pretty difficult to find the right documentation, so hopefully, this small blog post will sort it out.</div>]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[Just for note keeping, I've written down some methods of reducing the size of a .NET Core application. I thought others could use it as well, so here you go. Original Size First off, let's see how much disk space a self-contained 'hello world' application takes up. &gt; dotnet new console &gt; dotnet publish -r win-x86 -c release Size: 53.9 MB - yuck! Trimming Microsoft has built a tool that finds unused assemblies and removes them from the distribution package. This is much needed since the 'netcoreapp2.0' profile is basically .NET Framework all over again, and it contains a truckload of assemblies our little 'hello world' application don't use. &gt; dotnet new console &gt; dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.0-preview1-25818-01 &gt; dotnet publish -r win-x86 -c release /p:TrimUnusedDependencies=true Size: 15.8 MB Much better! Although, we have only removed unused assemblies - what about unused code? Linking The Mono team over at Xamarin has built a linker that can remove unused code from assemblies. If you only use List&lt;T&gt; from System.Collections.Generic.dll, why have HashSet&lt;T&gt; and all the other classes? This has a huge impact reflection obviously, so use with care. &gt; dotnet new console &gt; dotnet new nuget Open nuget.config and add &lt;add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /&gt; &gt; dotnet add package ILLink.Tasks -v 0.1.4-preview-981901 &gt; dotnet publish -r win-x86 -c release Size: 22.9 MB Not as good as trimming it seems, but definitely better than doing nothing. .NET Native In the world of C, we have a thing called 'static linking' which means all assemblies get linked into a single assembly. This is very nice for small applications or deployments that can't rely on existing assemblies on the system. C# does not have this feature, but with .NET Native we get something very close. .NET Native is actually a refactored runtime called CoreRT, which uses RyuJIT to create native assemblies. Getting it to work is not as easy as trimming or linking since unfortunately Microsoft only supports UWP as a native platform. .NET Core is therefore left out in the cold for now. 1. Download CMake 3.8 or later. I choose cmake-3.10.1-win64-x64.msi 2. Make sure you have Visual Studio 2017 with C++ support installed 3. Download the latest successful build. Check their Jenkins for commit hash. 4. Unpack the content to c:\corert\ 5. Open 'x64 Native Tools Command Prompt for VS 2017' 6. Now you should compile .NET Native: &gt; cd c:\corert &gt; build.bat release Note that it takes a long time to download missing packages and compile the whole project. 7. Create a new .NET Core project and add .NET Native msbuild targets: &gt; mkdir c:\test &gt; cd c:\test &gt; dotnet new console &gt; set IlcPath=c:\corert\bin\Windows_NT.x64.Release 8. edit test.csproj and add the two lines just before '&lt;/Project&gt;': &lt;Import Project="$(MSBuildSDKsPath)\Microsoft.NET.Sdk\Sdk\Sdk.targets" /&gt; &lt;Import Project="$(IlcPath)\build\Microsoft.NETCore.Native.targets" /&gt; &gt; dotnet publish -r win-x64 -c release Size: 3.95 MB Wow! Unused assembles and unused code has been removed and everything is statically compiled into an executable. Note that I used x64 and not x86 in the .NET Native build, as I'm not sure .NET Native supports x86 fully yet. Bonus: Trim and Link We can actually use both trimming and linking to reduce the size of the application further. It seems that the trimmer is better at finding unused assemblies than the linker is, but if we do both steps, the trimmer will remove assemblies and the linker will remove the dead code from the remaining assemblies. Just add both steps together like this: &gt; dotnet new console &gt; dotnet new nuget Open nuget.config and add &lt;add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /&gt; &gt; dotnet add package ILLink.Tasks -v 0.1.4-preview-981901 &gt; dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.0-preview1-25818-01 &gt; dotnet publish -r win-x86 -c release /p:TrimUnusedDependencies=true Size: 14.9 MB Final size is pretty much as low as it gets right now without native compilation. Conclusion We can easily reduce the size of self-contained .NET Core application, we just have to add the right packages and switches. Microsoft has changed the behaviour of the .NET Core project and publish system several times now, which has made pretty difficult to find the right documentation, so hopefully, this small blog post will sort it out.]]></summary></entry><entry><title type="html">Testing 36200 DNS servers</title><link href="https://genbox.github.io/2017/08/testing-36200-dns-servers.html" rel="alternate" type="text/html" title="Testing 36200 DNS servers" /><published>2017-08-12T14:47:00+00:00</published><updated>2017-08-12T14:47:43+00:00</updated><id>https://genbox.github.io/2017/08/testing-36200-dns-servers</id><content type="html" xml:base="https://genbox.github.io/2017/08/testing-36200-dns-servers.html"><![CDATA[<h2>
Introduction</h2>
DNS is an important part of the Internet and the speed and security are paramount for a good browsing experience. I thought it would be a good idea to scan the internet for DNS servers and test every single one of them. However, the latency of a particular DNS server depends highly on the distance and connection technology between you and the DNS server, and since I'm geographically located in Denmark, the results speed-wise only pertain to people located in/around Denmark.<br/>
<h2>
Testing methodology</h2>
I scanned the IPv4 Internet using <a href="https://nmap.org/" rel="noopener noreferrer" target="_blank">NMap</a> on port 53/UDP and stopped the scan after a few hours. The results were DNS 36200 servers, some of which are owned by ISPs, companies and a whole lot of private people. Since the IP scan was randomized, it should represent a good sample.<br/>
<br/>
Almost all DNS servers have some sort of caching mechanism that makes sure requested DNS names are kept for as long as the Time-To-Live (TTL) as defined by the domain owner. To ensure we don't just test a bunch of cached entries, we need to test uncached domains as well.<br/>
<br/>
Reliability is also important, so we need to register when a query is dropped. The drop might be from a router between us and the DNS server, or it might be the DNS server itself, so we can't exactly measure the reliability of a particular server, but a high rate of dropped packets will disqualify never the less.<br/>
<br/>
Security is also an important factor, and there are 2 main things to look for:<br/>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions" rel="noopener noreferrer" target="_blank">DNSSEC</a> validation support</li>
<li><a href="https://en.wikipedia.org/wiki/DNS_spoofing" rel="noopener noreferrer" target="_blank">DNS Spoofing</a> hardening</li>
</ul>
<h2>
Popular servers</h2>
<div>
There are a bunch of "known good" DNS servers out there that has a good reputation for being stable and fast. I added them to the list, just to make sure we test them as well.</div>
<div>
<ul>
<li>Google: 8.8.8.8</li>
<li>OpenDNS: 208.67.222.222</li>
<li>Level3: 4.2.2.1</li>
<li>UltraDNS: 156.154.70.1</li>
</ul>
<div>
Note that I did not add secondary clusters for each of the nameservers.</div>
</div>
<h2>
Performing the test</h2>
<div>
GRC has a <a href="https://www.grc.com/dns/benchmark.htm" rel="noopener noreferrer" target="_blank">DNS benchmark tool</a> that accomplishes the cached, non-cached and reliability tests, but it only supports 200 nameservers at the same time. I split the list into chunks and used the command line to automate checking 200 servers at the time.</div>
<div>
<br/></div>
<div>
After it finished running, I sorted the lists by average response time and ended up with the 200 fastest DNS servers. I then ran the test again on those servers and ended up with the 10 fastest DNS servers.</div>
<div>
<br/></div>
<div>
Each of those 10 servers then went through a DNSSEC validation test:</div>
<div>
<div>
<ul>
<li>dig sigok.verteiltesysteme.net @&lt;DNS IP HERE&gt;  (should return NOERROR)</li>
<li>dig sigfail.verteiltesysteme.net @&lt;DNS IP HERE&gt; (should return SERVFAIL)</li>
</ul>
<div>
The 10 servers were then subjected to the DNS spoofability test over at <a href="https://www.grc.com/dns/dns.htm" rel="noopener noreferrer" target="_blank">GRCs DNS page</a> to determine the source port and transaction ID entropy.</div>
</div>
</div>
<h2>
Results</h2>
<div>
The table below is ordered from fastest to slowest based on the average response time.</div>
<div>
<br/></div>
<div>
<table style="width: 100%;">
<thead align="left">
<tr>
<th>IP</th>
<th>Owner</th>
<th>DNSSEC validation</th>
<th>Anti-spoof</th>
</tr>
</thead>
<tbody>
<tr>
<td>195.215.95.11</td>
<td>TDC</td>
<td>Yes</td>
<td>Bad</td>
</tr>
<tr>
<td>89.233.43.71</td>
<td>censurfridns.dk</td>
<td>Yes</td>
<td>Bad</td>
</tr>
<tr>
<td>94.126.178.9</td>
<td>censurfridns.dk</td>
<td>Yes</td>
<td>Bad</td>
</tr>
<tr>
<td>94.143.10.52</td>
<td>dandomain.dk</td>
<td>No</td>
<td>Moderate</td>
</tr>
<tr>
<td>147.29.10.6</td>
<td>sdn.dk</td>
<td>No</td>
<td>Moderate</td>
</tr>
<tr>
<td>86.58.175.12</td>
<td>j.net</td>
<td>No</td>
<td>Excellent</td>
</tr>
<tr>
<td>194.239.10.180</td>
<td>webspeed.dk</td>
<td>No</td>
<td>Very bad</td>
</tr>
<tr>
<td>94.143.10.43</td>
<td>dandomain.dk</td>
<td>No</td>
<td>Moderate</td>
</tr>
<tr>
<td>193.219.27.222</td>
<td>ipweb.dk</td>
<td>No</td>
<td>N/A (rate limit)</td>
</tr>
<tr>
<td>195.190.31.129</td>
<td>Welcom Hosting Aps</td>
<td>Yes</td>
<td>Moderate</td>
</tr>
</tbody>
</table>
<br/>
If we take a look at just the popular DNS servers - as above, order by latency relative to my geographical location.<br/>
<br/>
<table style="width: 100%;">
<thead align="left">
<tr>
<th>IP</th>
<th>Owner</th>
<th>DNSSEC validation</th>
<th>Alti-spoof</th>
</tr>
</thead>
<tbody>
<tr>
<td>8.8.8.8</td>
<td>Google</td>
<td>Yes</td>
<td>Moderate</td>
</tr>
<tr>
<td>4.2.2.1</td>
<td>Level3</td>
<td>No</td>
<td>Excellent</td>
</tr>
<tr>
<td>208.67.222.222</td>
<td>OpenDNS</td>
<td>No</td>
<td>Excellent</td>
</tr>
<tr>
<td>156.154.70.1</td>
<td>UltraDNS</td>
<td>Yes</td>
<td>Excellent</td></tr>
</tbody></table>
</div>
<h2>
Conclusion</h2>
It seems TDC's DNS server is the fastest but unfortunately it has bad anti-spoofing capabilities. It seems there is no clear winner regarding speed and security. UltraDNS has the best security but was also the slowest (70% slower than TDC) of the servers in relation to my geographical location. I'm sure that people located closer to the servers will have lower latency, and then UltraDNS becomes the clear winner.<br/>
<br/>
In the end, there is little to no difference between the top 10 DNS servers and even the 4 popular servers. Run a test yourself to see just how big the difference is between your current DNS server and the popular ones, maybe there is better latency and a little more secuirty to get.]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[Introduction DNS is an important part of the Internet and the speed and security are paramount for a good browsing experience. I thought it would be a good idea to scan the internet for DNS servers and test every single one of them. However, the latency of a particular DNS server depends highly on the distance and connection technology between you and the DNS server, and since I'm geographically located in Denmark, the results speed-wise only pertain to people located in/around Denmark. Testing methodology I scanned the IPv4 Internet using NMap on port 53/UDP and stopped the scan after a few hours. The results were DNS 36200 servers, some of which are owned by ISPs, companies and a whole lot of private people. Since the IP scan was randomized, it should represent a good sample. Almost all DNS servers have some sort of caching mechanism that makes sure requested DNS names are kept for as long as the Time-To-Live (TTL) as defined by the domain owner. To ensure we don't just test a bunch of cached entries, we need to test uncached domains as well. Reliability is also important, so we need to register when a query is dropped. The drop might be from a router between us and the DNS server, or it might be the DNS server itself, so we can't exactly measure the reliability of a particular server, but a high rate of dropped packets will disqualify never the less. Security is also an important factor, and there are 2 main things to look for: DNSSEC validation support DNS Spoofing hardening Popular servers There are a bunch of "known good" DNS servers out there that has a good reputation for being stable and fast. I added them to the list, just to make sure we test them as well. Google: 8.8.8.8 OpenDNS: 208.67.222.222 Level3: 4.2.2.1 UltraDNS: 156.154.70.1 Note that I did not add secondary clusters for each of the nameservers. Performing the test GRC has a DNS benchmark tool that accomplishes the cached, non-cached and reliability tests, but it only supports 200 nameservers at the same time. I split the list into chunks and used the command line to automate checking 200 servers at the time. After it finished running, I sorted the lists by average response time and ended up with the 200 fastest DNS servers. I then ran the test again on those servers and ended up with the 10 fastest DNS servers. Each of those 10 servers then went through a DNSSEC validation test: dig sigok.verteiltesysteme.net @&lt;DNS IP HERE&gt;  (should return NOERROR) dig sigfail.verteiltesysteme.net @&lt;DNS IP HERE&gt; (should return SERVFAIL) The 10 servers were then subjected to the DNS spoofability test over at GRCs DNS page to determine the source port and transaction ID entropy. Results The table below is ordered from fastest to slowest based on the average response time. IP Owner DNSSEC validation Anti-spoof 195.215.95.11 TDC Yes Bad 89.233.43.71 censurfridns.dk Yes Bad 94.126.178.9 censurfridns.dk Yes Bad 94.143.10.52 dandomain.dk No Moderate 147.29.10.6 sdn.dk No Moderate 86.58.175.12 j.net No Excellent 194.239.10.180 webspeed.dk No Very bad 94.143.10.43 dandomain.dk No Moderate 193.219.27.222 ipweb.dk No N/A (rate limit) 195.190.31.129 Welcom Hosting Aps Yes Moderate If we take a look at just the popular DNS servers - as above, order by latency relative to my geographical location. IP Owner DNSSEC validation Alti-spoof 8.8.8.8 Google Yes Moderate 4.2.2.1 Level3 No Excellent 208.67.222.222 OpenDNS No Excellent 156.154.70.1 UltraDNS Yes Excellent Conclusion It seems TDC's DNS server is the fastest but unfortunately it has bad anti-spoofing capabilities. It seems there is no clear winner regarding speed and security. UltraDNS has the best security but was also the slowest (70% slower than TDC) of the servers in relation to my geographical location. I'm sure that people located closer to the servers will have lower latency, and then UltraDNS becomes the clear winner. In the end, there is little to no difference between the top 10 DNS servers and even the 4 popular servers. Run a test yourself to see just how big the difference is between your current DNS server and the popular ones, maybe there is better latency and a little more secuirty to get.]]></summary></entry><entry><title type="html">Secure Hashing of Passwords</title><link href="https://genbox.github.io/2016/12/secure-hashing-of-passwords.html" rel="alternate" type="text/html" title="Secure Hashing of Passwords" /><published>2016-12-09T16:35:00+00:00</published><updated>2016-12-18T01:34:32+00:00</updated><id>https://genbox.github.io/2016/12/secure-hashing-of-passwords</id><content type="html" xml:base="https://genbox.github.io/2016/12/secure-hashing-of-passwords.html"><![CDATA[Numerous breaches happen every day due to security vulnerabilities. On this blog, I have previously analyzed some of the biggest breaches that have been made public. All of them serve as a testament to the inadequate security many companies employ.<br/>
<br/>
<h2>
The Time it Takes to Crack a Hash</h2>
I often get asked: "How long does it take to crack an MD5 hash?" - implying that the cryptographic hash algorithm is the most important factor, which rarely is the case. It actually depends on a couple of factors, which I've ordered in descending importance below:<br/>
<ol>
<li>The length of the password</li>
<li>The charsets used in the password</li>
<li>The amount of hardware you have</li>
<li>The methodology you use for cracking</li>
</ol>
<h3>
Secure Passwords</h3>
Password lengths alone are not enough, you also have to use a good charset to control the search space hackers have to go though. Let's make an example to show how much the search space changes:<br/>
<br/>
Charset = a-z, A-Z, 0-9<br/>
Length 6: (26+26+10)^6 = 56.800.235.584<br/>
Length 7: (26+26+10)^7 = 3.521.614.606.208<br/>
Length 8: (26+26+10)^8 = 218.340.105.584.896<br/>
<br/>
As you can see, the number gets a lot bigger for each character we add. Now lets look at charsets:<br/>
<br/>
Length = 8<br/>
Charset: a-z = (26)^8 = 208.827.064.576<br/>
Charset: a-z, A-Z = (26+26)^8 = 53.459.728.531.456<br/>
Charset: a-z, A-Z, 0-9 = (26+26+10)^8 = 218.340.105.584.896<br/>
<br/>
Charsets are at least as important as the length is. In reality, we need to increase both in other to get good passwords. For reference, MD5 hashes on a Nvidia Titan X graphics card can be cracked with around 15.000.000.000 hashes per second. A password of a-z, A-Z, 0-9 of length 8 would take (26+26+10)^8 / 15.000.000.000 = 14556 seconds (about 4 hours). That is not long enough to deter hackers - we need to do something about the hashing algorithm as well.<br/>
<br/>
<h2>
The Cryptographic Hash Algorithms</h2>
Through time, developers have used many different cryptographic hash algorithms to store passwords. Actually, most systems still use rather weak hash algorithms, which is why this blog post even exist. If we take a look at the hashing algorithms from strong to weak:<br/>
<br/>
1. scrypt, bcrypt, PBKDF2<br/>
2. SHA512, SHA256<br/>
3. SHA1, MD5<br/>
4. NTLM, MD4<br/>
5. LM, DES (unix crypt)<br/>
<br/>
I could write 100 blog posts about each algorithm, but suffice to say that LM and DES used to be VERY widespread in the days of Windows XP and Linux 2.x. They have since moved on to stronger algorithms, but Windows is stuck on NTLM, and Linux still use MD5, SHA256 and SHA512 for the most part, but is transitioning nicely to scrypt and PBKDF2.<br/>
<br/>
You might be wondering what the speeds are of each algorithm, so I'll include each of them here. A larger number of hashes is worse. The speeds are from a Nvidia Geforce 1080 graphics card with Hashcat:<br/>
<ol>
<li>scrypt - 434.000 H/s</li>
<li>bcrypt - 13.226 H/s</li>
<li>PBKDF2 (SHA1) - 3218.000 H/s</li>
<li>SHA512 - 1.021.000.000 H/s</li>
<li>SHA256 - 2.829.000.000 H/s</li>
<li>SHA1 - 8.491.000.000 H/s</li>
<li>MD5 - 24.809.000.000 H/s</li>
<li>NTLM - 41.354.000.000 H/s</li>
<li>MD4 - 43.145.000.000 H/s</li>
<li>LM - 18.429.000.000 H/s</li>
<li>DES - 909.000.000 H/s</li>
</ol>
You might say: Hold on a minute! DES is actually slower than SHA512, does that not mean it is more secure?<br/>
<br/>
Nope! That's because the way the Linux guys implemented DES limited it a maximum of 8 characters, and they are also using the 2 first characters as salt, which means we only need to crack 6 character long passwords. LM hashes are also limited to 14 characters, but the way Microsoft made the algorithm is flawed, and as such, we only need to crack 2x7 character passwords.<br/>
<br/>
<h2>
The Salted Hash</h2>
Password salts are needed in order to protect against <a href="/2012/01/the-power-of-rainbow-tables.html" rel="noopener noreferrer" target="_blank">rainbow table attacks</a>. Hackers have access to large precomputed tables of character sets in many different cryptographic hash algorithms today, and when they target just a single hash, it can be quite effective.<br/>
<br/>
The salt is just a binary blob that gets appended to the password in the hashing process. A password of '123456' becomes '123456[SaltHere]', thereby making it impossible to precompute a table that contains '123456[SaltHere]'. Salts should be unique for each user in the database, thereby making the protection even more effective.<br/>
<br/>
The right way to salt the password is to use a cryptographically secure pseudo-random number generator (<a href="http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator" rel="noopener noreferrer" target="_blank">CSPRNG</a>) to create a salt which is unique for each user. It needs to be at least 64 bits (8 bytes) to be effective. The salt is stored together with the hash inside the user database in plain text.<br/>
<br/>
<h2>
The Slow Hash</h2>
Cryptographic hash functions like MD5 and SHA1 are designed with high performance in mind. This means that they can quickly produce a hash of an arbitrary input, but it also means that they are good for brute force and wordlist attacks. To slow down the hashing procedure, we use something called a key derivation function (<a href="http://en.wikipedia.org/wiki/Key_derivation_function" rel="noopener noreferrer" target="_blank">KDF</a>). <a href="https://en.wikipedia.org/wiki/Scrypt" rel="noopener noreferrer" target="_blank">scrypt</a>, <a href="https://en.wikipedia.org/wiki/Bcrypt" rel="noopener noreferrer" target="_blank">bcrypt</a> and <a href="http://en.wikipedia.org/wiki/PBKDF2" rel="noopener noreferrer" target="_blank">PBKDF2</a> are such a function. They take in a password, a salt and a number of iterations. Most implementations actually just require a password and a "workload factor", which simplifies the use of the algorithms.<br/>
<br/>
They work by cryptographic primitives like SHA1, SHA256 or Blowfish, which is then run the number of iterations together with a salt. They also apply the salt in an <a href="https://en.wikipedia.org/wiki/Hash-based_message_authentication_code" rel="noopener noreferrer" target="_blank">HMAC </a>fashion to be completely secure against many different cryptographic hash attacks.<br/>
<br/>
As you can see from the hash speed list above, scrypt, bcrypt and PBKDF2 are much, much slower than their relatives. This is very configurable and perfect for password hashing. Developers that implement these algorithms should aim for the number of iterations it takes to make a password hashing operation last 50 ms or more on their server.<br/>
<br/>
If we take the example of a 8 character password with the charset a-z, A-Z, 0-9 from above, which took 4 hours to crack with MD5, and try to crack it using PBKDF2, it would take around 2 years to crack!<br/>
<br/>
<h2>
Conclusion</h2>
Use scrypt, bcrypt or PBKDF2 with a high enough work factor that it takes at least 50 ms to compute a single hash on your server. It takes care of hashing the correct way, applying a salt and usually uses a CSPRNG to generate the salt. Stay away from everything else.]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[Numerous breaches happen every day due to security vulnerabilities. On this blog, I have previously analyzed some of the biggest breaches that have been made public. All of them serve as a testament to the inadequate security many companies employ. The Time it Takes to Crack a Hash I often get asked: "How long does it take to crack an MD5 hash?" - implying that the cryptographic hash algorithm is the most important factor, which rarely is the case. It actually depends on a couple of factors, which I've ordered in descending importance below: The length of the password The charsets used in the password The amount of hardware you have The methodology you use for cracking Secure Passwords Password lengths alone are not enough, you also have to use a good charset to control the search space hackers have to go though. Let's make an example to show how much the search space changes: Charset = a-z, A-Z, 0-9 Length 6: (26+26+10)^6 = 56.800.235.584 Length 7: (26+26+10)^7 = 3.521.614.606.208 Length 8: (26+26+10)^8 = 218.340.105.584.896 As you can see, the number gets a lot bigger for each character we add. Now lets look at charsets: Length = 8 Charset: a-z = (26)^8 = 208.827.064.576 Charset: a-z, A-Z = (26+26)^8 = 53.459.728.531.456 Charset: a-z, A-Z, 0-9 = (26+26+10)^8 = 218.340.105.584.896 Charsets are at least as important as the length is. In reality, we need to increase both in other to get good passwords. For reference, MD5 hashes on a Nvidia Titan X graphics card can be cracked with around 15.000.000.000 hashes per second. A password of a-z, A-Z, 0-9 of length 8 would take (26+26+10)^8 / 15.000.000.000 = 14556 seconds (about 4 hours). That is not long enough to deter hackers - we need to do something about the hashing algorithm as well. The Cryptographic Hash Algorithms Through time, developers have used many different cryptographic hash algorithms to store passwords. Actually, most systems still use rather weak hash algorithms, which is why this blog post even exist. If we take a look at the hashing algorithms from strong to weak: 1. scrypt, bcrypt, PBKDF2 2. SHA512, SHA256 3. SHA1, MD5 4. NTLM, MD4 5. LM, DES (unix crypt) I could write 100 blog posts about each algorithm, but suffice to say that LM and DES used to be VERY widespread in the days of Windows XP and Linux 2.x. They have since moved on to stronger algorithms, but Windows is stuck on NTLM, and Linux still use MD5, SHA256 and SHA512 for the most part, but is transitioning nicely to scrypt and PBKDF2. You might be wondering what the speeds are of each algorithm, so I'll include each of them here. A larger number of hashes is worse. The speeds are from a Nvidia Geforce 1080 graphics card with Hashcat: scrypt - 434.000 H/s bcrypt - 13.226 H/s PBKDF2 (SHA1) - 3218.000 H/s SHA512 - 1.021.000.000 H/s SHA256 - 2.829.000.000 H/s SHA1 - 8.491.000.000 H/s MD5 - 24.809.000.000 H/s NTLM - 41.354.000.000 H/s MD4 - 43.145.000.000 H/s LM - 18.429.000.000 H/s DES - 909.000.000 H/s You might say: Hold on a minute! DES is actually slower than SHA512, does that not mean it is more secure? Nope! That's because the way the Linux guys implemented DES limited it a maximum of 8 characters, and they are also using the 2 first characters as salt, which means we only need to crack 6 character long passwords. LM hashes are also limited to 14 characters, but the way Microsoft made the algorithm is flawed, and as such, we only need to crack 2x7 character passwords. The Salted Hash Password salts are needed in order to protect against rainbow table attacks. Hackers have access to large precomputed tables of character sets in many different cryptographic hash algorithms today, and when they target just a single hash, it can be quite effective. The salt is just a binary blob that gets appended to the password in the hashing process. A password of '123456' becomes '123456[SaltHere]', thereby making it impossible to precompute a table that contains '123456[SaltHere]'. Salts should be unique for each user in the database, thereby making the protection even more effective. The right way to salt the password is to use a cryptographically secure pseudo-random number generator (CSPRNG) to create a salt which is unique for each user. It needs to be at least 64 bits (8 bytes) to be effective. The salt is stored together with the hash inside the user database in plain text. The Slow Hash Cryptographic hash functions like MD5 and SHA1 are designed with high performance in mind. This means that they can quickly produce a hash of an arbitrary input, but it also means that they are good for brute force and wordlist attacks. To slow down the hashing procedure, we use something called a key derivation function (KDF). scrypt, bcrypt and PBKDF2 are such a function. They take in a password, a salt and a number of iterations. Most implementations actually just require a password and a "workload factor", which simplifies the use of the algorithms. They work by cryptographic primitives like SHA1, SHA256 or Blowfish, which is then run the number of iterations together with a salt. They also apply the salt in an HMAC fashion to be completely secure against many different cryptographic hash attacks. As you can see from the hash speed list above, scrypt, bcrypt and PBKDF2 are much, much slower than their relatives. This is very configurable and perfect for password hashing. Developers that implement these algorithms should aim for the number of iterations it takes to make a password hashing operation last 50 ms or more on their server. If we take the example of a 8 character password with the charset a-z, A-Z, 0-9 from above, which took 4 hours to crack with MD5, and try to crack it using PBKDF2, it would take around 2 years to crack! Conclusion Use scrypt, bcrypt or PBKDF2 with a high enough work factor that it takes at least 50 ms to compute a single hash on your server. It takes care of hashing the correct way, applying a salt and usually uses a CSPRNG to generate the salt. Stay away from everything else.]]></summary></entry><entry><title type="html">The problem with Network Address Translation</title><link href="https://genbox.github.io/2016/12/the-problem-with-network-address.html" rel="alternate" type="text/html" title="The problem with Network Address Translation" /><published>2016-12-03T11:41:00+00:00</published><updated>2016-12-18T01:36:36+00:00</updated><id>https://genbox.github.io/2016/12/the-problem-with-network-address</id><content type="html" xml:base="https://genbox.github.io/2016/12/the-problem-with-network-address.html"><![CDATA[As a technology ideologist, <a href="https://en.wikipedia.org/wiki/Network_address_translation" rel="noopener noreferrer" target="_blank">Network Address Translation</a> (NAT) is one of my biggest concerns when it comes to the future of the Internet. The Internet was built as a communications tool to facilitate the sharing of information in digital form. It has vastly improved the communication between humans around the planet and it has been one of the most important inventions we have ever made.<br/>
<br/>
My concerns is with the fact that NAT is a direct inhibitor of the nature of the Internet, which goes against everything we want the Internet to be.<br/>
<br/>
<h2>
Network Address Translation</h2>
The Internet uses routers to route data from network to network, but to do so, we need addresses of each network. Today we use <a href="https://en.wikipedia.org/wiki/IPv4" rel="noopener noreferrer" target="_blank">Internet Protocol version 4</a> (IPv4), which you usually see in dottet format such as 199.181.132.250. In its raw form, IPv4 is a 32 bit (4 bytes) addressing scheme which is able to address 2^32 (4.294.967.296) networks, which was enough back when the Internet was created in the 1950s, but it is nowhere near enough for the Internet today. To solve this problem, <a href="https://en.wikipedia.org/wiki/Ipv6" rel="noopener noreferrer" target="_blank">Internet Protocol version 6</a> (IPv6) was created, which has 128 bits that give us 2^128 (340.282.366.920.938.463.463.374.607.431.768.211.456) addresses, which should be enough to last us for a long time.<br/>
<br/>
Routers need a firmware upgrade in order to route 128-bit addresses, and back in the day when IPv6 was devised (1998), routers simply did not have the capacity to route the larger address space. A quick workaround was to create NAT, which is a simple mechanism to translate one address to another. With this capability, Internet Service Providers (ISP) began to distribute routers pre-configured with NAT enabled. They had DHCP enabled on the LAN interface with <a href="https://en.wikipedia.org/wiki/Private_network" rel="noopener noreferrer" target="_blank">non-routed IP addresses</a> (192.168.0.0/24), which then got translated to a routed IP address on the WAN interface. This allowed ISPs to extend the lifetime of IPv4 and keep using low capacity consumer routers.<br/>
<br/>
That does not sound too bad, right? It is a clever way to circumvent the limitations of IPv4 and keep using existing hardware which was produced for cheap in large quantities.<br/>
<br/>
<h2>
The Problem</h2>
A side-effect of NAT is that it splits the Internet into many smaller private networks, which can't communicate directly with each other unless you do <a href="https://en.wikipedia.org/wiki/Port_forwarding" rel="noopener noreferrer" target="_blank">port forwarding</a>. This side effect has been documented as a "security feature" ever since it was conceived, as it essentially functions like a simple firewall between networks.<br/>
<br/>
Remember what the purpose of the Internet was? That's right, to transmit digital information between machines! NAT completely contradicts the whole purpose of the Internet by segmenting the Internet, just because we saw NAT as a quick fix to our IPv4 addressing problem. We have become accustomed to the fact that NAT exists. It has served its purpose, and it is time we move on to IPv6 and make the Internet work as intended again.<br/>
<br/>
<h2>
The Solution</h2>
By now you should already know that IPv6 is the solution to the NAT problem, but there is still an unanswered question: What about the security NAT provides?<br/>
<br/>
Let me counter-question you with this: What is it we are trying to achieve?<br/>
<br/>
I'd agree that the Internet should not just be one big monolithic security boundary, where any hosted service can be reached by everyone else. That is why we have firewalls, which NAT is not. You still have a router with two networks, and in other to publish a service from one network to the other, a firewall will have to allow it. Firewalls are a much more efficient solution to the security problem than NAT is.<br/>
<h2>
</h2>
Let's say we enabled IPv6, what exactly would that mean?<br/>
<br/>
That is the funny part; you are <b>already </b>running IPv6! That's right, you are running a dual-stacked network layer capable of both IPv4 and IPv6, you don't have to do anything. Most routers are also already dual-stacked, we just have to disable IPv4 and tadaaaa, you are IPv6 only.<br/>
<br/>
For router manufacturers, developers and network engineers it is a <b>huge </b>advantage to completely disable IPv4, which is why many ISPs today are running IPv6-only networks internally. As a manufacturer or developer, you can remove NAT, <a href="https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT" rel="noopener noreferrer" target="_blank">TURN</a>, <a href="https://en.wikipedia.org/wiki/STUN" rel="noopener noreferrer" target="_blank">STUN</a>, <a href="https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol" rel="noopener noreferrer" target="_blank">IGDP</a> and <a href="https://en.wikipedia.org/wiki/NAT_Port_Mapping_Protocol" rel="noopener noreferrer" target="_blank">NAT-PMP</a> from routers and communication software. Of course, we still need a network control protocol that publishes a service in the router's firewall, but it is so much more simple now that you don't have to take NAT into account.<br/>
<br/>
<h2>
A Real Example</h2>
The BitTorrent protocol is one of the most common occurring protocols on the Internet. It is a simple protocol to transmit binary data between clients in an efficient manner using Peer to Peer (P2P). Clients find each other by using a Tracker or what's known as a <a href="https://en.wikipedia.org/wiki/Distributed_hash_table" rel="noopener noreferrer" target="_blank">Distributed Hash Table</a> (DHT). DHT is a simple protocol, but it is severely limited by NAT, simply by the fact that it works in a very socialistic manner. Each client in the DHT network has to store a chunk of data for it to work, but since most of them now sits behind NAT-enabled routers, they can't be reached by the rest of the network, thereby making the data they contain unreachable by others. This fundamentally destroys the whole concept of a Distributed Hash Table! All BitTorrent applications have implemented one of the many protocols to circumvent NAT, but none of them are perfect. If we switched to IPv6 only networks, DHTs can finally work again, and we would see a massive gain in performance as clients can find each other more efficiently.<br/>
<br/>
Other P2P protocols like Skype would also work better and would not have to route through a third party. Back in 2011 when Microsoft bought Skype, they began transitioning the Skype P2P protocol from a highly distributed node network into a more centralized platform based on <a href="https://en.wikipedia.org/wiki/Microsoft_Notification_Protocol" rel="noopener noreferrer" target="_blank">Microsoft Notification Protocol</a> (MSNP). The centralized protocol works "better" because Microsoft's servers work as a broker between you and other clients, thereby circumventing NAT. If the clients both have IPv6 and publishes the Skype service in their router firewall, they could reach each other directly, and instantly get a massive performance and stability gain.<br/>
<br/>
Maybe this is just wishful thinking, but it does seem that the <a href="https://www.google.com/intl/en/ipv6/statistics.html" rel="noopener noreferrer" target="_blank">IPv6 adoption</a> is gaining speed, which is good news for the internet as a whole.]]></content><author><name>Ian Qvist</name></author><summary type="html"><![CDATA[As a technology ideologist, Network Address Translation (NAT) is one of my biggest concerns when it comes to the future of the Internet. The Internet was built as a communications tool to facilitate the sharing of information in digital form. It has vastly improved the communication between humans around the planet and it has been one of the most important inventions we have ever made. My concerns is with the fact that NAT is a direct inhibitor of the nature of the Internet, which goes against everything we want the Internet to be. Network Address Translation The Internet uses routers to route data from network to network, but to do so, we need addresses of each network. Today we use Internet Protocol version 4 (IPv4), which you usually see in dottet format such as 199.181.132.250. In its raw form, IPv4 is a 32 bit (4 bytes) addressing scheme which is able to address 2^32 (4.294.967.296) networks, which was enough back when the Internet was created in the 1950s, but it is nowhere near enough for the Internet today. To solve this problem, Internet Protocol version 6 (IPv6) was created, which has 128 bits that give us 2^128 (340.282.366.920.938.463.463.374.607.431.768.211.456) addresses, which should be enough to last us for a long time. Routers need a firmware upgrade in order to route 128-bit addresses, and back in the day when IPv6 was devised (1998), routers simply did not have the capacity to route the larger address space. A quick workaround was to create NAT, which is a simple mechanism to translate one address to another. With this capability, Internet Service Providers (ISP) began to distribute routers pre-configured with NAT enabled. They had DHCP enabled on the LAN interface with non-routed IP addresses (192.168.0.0/24), which then got translated to a routed IP address on the WAN interface. This allowed ISPs to extend the lifetime of IPv4 and keep using low capacity consumer routers. That does not sound too bad, right? It is a clever way to circumvent the limitations of IPv4 and keep using existing hardware which was produced for cheap in large quantities. The Problem A side-effect of NAT is that it splits the Internet into many smaller private networks, which can't communicate directly with each other unless you do port forwarding. This side effect has been documented as a "security feature" ever since it was conceived, as it essentially functions like a simple firewall between networks. Remember what the purpose of the Internet was? That's right, to transmit digital information between machines! NAT completely contradicts the whole purpose of the Internet by segmenting the Internet, just because we saw NAT as a quick fix to our IPv4 addressing problem. We have become accustomed to the fact that NAT exists. It has served its purpose, and it is time we move on to IPv6 and make the Internet work as intended again. The Solution By now you should already know that IPv6 is the solution to the NAT problem, but there is still an unanswered question: What about the security NAT provides? Let me counter-question you with this: What is it we are trying to achieve? I'd agree that the Internet should not just be one big monolithic security boundary, where any hosted service can be reached by everyone else. That is why we have firewalls, which NAT is not. You still have a router with two networks, and in other to publish a service from one network to the other, a firewall will have to allow it. Firewalls are a much more efficient solution to the security problem than NAT is. Let's say we enabled IPv6, what exactly would that mean? That is the funny part; you are already running IPv6! That's right, you are running a dual-stacked network layer capable of both IPv4 and IPv6, you don't have to do anything. Most routers are also already dual-stacked, we just have to disable IPv4 and tadaaaa, you are IPv6 only. For router manufacturers, developers and network engineers it is a huge advantage to completely disable IPv4, which is why many ISPs today are running IPv6-only networks internally. As a manufacturer or developer, you can remove NAT, TURN, STUN, IGDP and NAT-PMP from routers and communication software. Of course, we still need a network control protocol that publishes a service in the router's firewall, but it is so much more simple now that you don't have to take NAT into account. A Real Example The BitTorrent protocol is one of the most common occurring protocols on the Internet. It is a simple protocol to transmit binary data between clients in an efficient manner using Peer to Peer (P2P). Clients find each other by using a Tracker or what's known as a Distributed Hash Table (DHT). DHT is a simple protocol, but it is severely limited by NAT, simply by the fact that it works in a very socialistic manner. Each client in the DHT network has to store a chunk of data for it to work, but since most of them now sits behind NAT-enabled routers, they can't be reached by the rest of the network, thereby making the data they contain unreachable by others. This fundamentally destroys the whole concept of a Distributed Hash Table! All BitTorrent applications have implemented one of the many protocols to circumvent NAT, but none of them are perfect. If we switched to IPv6 only networks, DHTs can finally work again, and we would see a massive gain in performance as clients can find each other more efficiently. Other P2P protocols like Skype would also work better and would not have to route through a third party. Back in 2011 when Microsoft bought Skype, they began transitioning the Skype P2P protocol from a highly distributed node network into a more centralized platform based on Microsoft Notification Protocol (MSNP). The centralized protocol works "better" because Microsoft's servers work as a broker between you and other clients, thereby circumventing NAT. If the clients both have IPv6 and publishes the Skype service in their router firewall, they could reach each other directly, and instantly get a massive performance and stability gain. Maybe this is just wishful thinking, but it does seem that the IPv6 adoption is gaining speed, which is good news for the internet as a whole.]]></summary></entry></feed>