tag:blogger.com,1999:blog-91013115292216822322024-03-20T18:52:59.649-07:00coop.softwareRobert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-9101311529221682232.post-23205484856946101042021-01-09T10:34:00.006-08:002021-01-09T18:20:11.069-08:00Cigarettes Don't Cause Cancer<h2 style="text-align: left;"> Cigarettes Don't Cause Cancer</h2><p>...except they do. Of course they do. It was 1964 when the Surgeon General of the United States first declared, based on thousands of published studies at the time, that cigarettes cause cancer. The thing is, between 1964 and <a href="https://www.latimes.com/archives/la-xpm-1997-03-21-mn-40672-story.html">1997</a> there was a giant industry that completely denied it. Indeed, it wasn't until <a href="https://www.theatlantic.com/politics/archive/2016/05/low-tar-cigarettes/481116/">2010</a> that they admitted that "Light" cigarettes weren't less of a cancer risk. That industry paid lawyers to sue people who said it, and lobbyists to give money to politicians who said it. Republican politicians, making Big Tobacco <a href="https://edition.cnn.com/2009/POLITICS/06/19/tobacco.decline/#:~:text=(CNN)%20%2D%2D%20In%20the%201960s,for%20effective%20special%2Dinterest%20lobbying.&text=The%20industry%20was%20known%20for,ties%20to%20major%20power%20players.">"the model for effective special-interest lobbying"</a>.</p><p>This through through the 1970s and 1980s -- well after medical science had settled the matter -- "Cigarettes don't cause cancer" was part of the Republican Party orthodoxy. Rush Limbaugh, who began broadcasting during this heyday continued to maintain that lie to his millions of conservative listeners, even still decrying smoking bans in 2015. Limbaugh, at the time of this writing has stage 4 lung cancer. </p><h2 style="text-align: left;">Condoms Don't Work</h2><p>Of course, the 1980s brought with it another health crisis in the United States... HIV/AIDS. Originally covered in the press as GRID (gay-related immune deficiency) it was largely ignored by the Reagan administration. But for the conservative Christian groups that had come to power in the Republican Party in the late 70s, it was just comeuppance for those queers. The Reverend Billy Graham, known as one of the more reasonable to the evangelical leaders said, "Is AIDS a judgement of God? I could not say for sure, but I think so." Once again, the Surgeon General pipes up and begins explaining that condoms are the most effective way to prevent the transmission of this new disease. Health classes in schools began teaching about "safe(r) sex" and how to prevent the transmission of HIV.</p><p>This, of course, was an outrage. The phrase "Abstinence only sex-education" enters the national lexicon. Just after organized prayer was largely removed from public schools, the conservative Christians, and their Republican Party representatives were not going to have kids taught about sex before marriage. They began d<a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5913747/#:~:text=Abstinence%2Donly%20curricula%20have%20been,efficacy%2C%20and%20promote%20gender%20stereotypes.&text=Abstinence%2Donly%20polices%20violate%20the,on%20HIV%20and%20other%20STIs.">istributing literature saying that abstinence</a> was 100% effective (true) and that condoms failed 50% of the time (false) and weren't effective at preventing STIs (false). The reality soon caught up to them as HIV rates, as well a teenage and unwanted pregnancy rates began to fall precipitously. This better reality didn't stop Republican lawmakers from introducing abstinence only education bills up until present day.</p><h2 style="text-align: left;">Global Warming isn't Real</h2><p>First becoming of concern in the late 1960s as the rate of CO<sub>2</sub> grown in the atmosphere was discovered, climate change became a real issue in the early to mid-1990s. Lateral drilling technologies had dramatically pushed "Peak Oil" into the future again and fuel prices were nowhere near their "Oil Shock" OPEC-driven crisis levels of the 70s and 80s. Advances in computation and observability, however began to make clear that the continued expansion of CO<sub>2</sub> in the atmosphere was not sustainable and will lead to dramatic climatic shifts in the medium term. At first, this was widely seen as a matter of global import by the US government. However, as soon as "Big Oil" began throwing money around, the denial of the fact that CO<sub>2</sub> absorbs infrared radiation became a new part of the Republican orthodoxy, and it remains so until this day.<br /><br />Also, you know, Al Gore talked about it, so it had to be an evil leftist conspiracy.</p><h2 style="text-align: left;">...Stop the Steal!</h2><div>Lying about policy seems to only have continued to escalate since then. “Most of the tax reductions go to the people at the bottom end of the economic ladder." "Saddam Hussein recently sought significant quantities of uranium from Africa." "Heck of a job, Brownie." "Barrack Obama was born in Kenya." These lies have become a fundamental part of the Republican Party identity a this point, even though all of these lies are blatantly, plainly false, and have been since the moment they were uttered, like the previous ones. </div><div><br /></div><div>But starting with "cigarettes don't cause cancer", the Republican Party leadership primed their followers to reject the obvious evidence against what they said. That "experts" are not to be trusted. And buoyed by Fox News, they had an entire mediasphere where they would never even be confronted with these obvious truths. Everyone else was a liar. E<a href="https://www.ajc.com/news/local-govt--politics/gingrich-language-set-new-course/O5bgK6lY2wQ3KwEZsYTBlO/">veryone else was "sick" and seeking to "destroy this country"</a>. The kind of madness, that used to be confined to The John Birch Society and their conspiracy theories about public water fluoridation, was now orthodoxy for one of the two major political parties.</div><div><br /></div><div>Republican voters across the country have been primed to believe lies for two generations now, and were simply ripened fruit when a literal confidence artist came for them. After the January 6 assault on the Capitol building, there has been an upwelling of "How did this happen?" on the political right -- well, the portion of the political right that doesn't want to keep the con game going full steam ahead. Mitt Romney apparently finger-wagged Ted Cruz about the stunt attempting to de-certify the results of the last election, but that was just the proximate event. Something like this was going to happen one way of the other. The outraged built on a foundation of lies was just too big on the right for this to not happen. As Voltaire said, "Those that can make you believe absurdities can make you commit atrocities."</div><div><br /></div><div>The real question is, are Republican leaders going to own up to the lies? Are they, are the right-wing media, going to explain to their constituents and viewers that they have been feeding them a line of bullshit for 40 years? </div>Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-70452504180638728772020-05-06T20:16:00.002-07:002020-06-09T08:34:14.097-07:00Public Key Infrastructure: What You Need to Know<h1 class="c15" id="h.yhvvmtyzjif9" style="break-after: avoid; font-family: Arial; font-size: 20pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 20pt;">
Public Key Infrastructure: What You Need to Know</h1>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Asymmetric, or "Public Key" cryptography underpins how much of modern computing works, but it isn't always well understood past "this is secure, and this isn't". In this post we are going to look at how public key cryptography works at four different levels: 1) A functional/conceptual level. 2) A protocol/operations level. 3) A (very basic) mathematical level. 4) Some common operational knowledge you should have.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c32" style="font-family: Arial; font-size: 11pt; line-height: 1; padding-bottom: 0pt; padding-top: 4pt;">
<span style="font-size: 16pt;">What's the big idea?</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Whether it was Julius Caesar creating "ROT-13" to communicate with his troops in the field, or the Enigma machine used in World War 2 by the Axis powers to communicate -- a device that, in its way, precipitated modern computing -- the practice of cryptography, or communicating securely, was always based on a shared secret. Something that the two parties who wished to communicate had to agree upon before the communication started. Whether it was "move forward 13 characters in the alphabet", or "configure the dials of your machine this way", the parties that wished to talk to each other securely had to securely (usually in person), agree on this shared secret.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This is problematic if you have two people who want to communicate with each other who haven't been physically proximate to agree on what the shared secret should be. When you want to talk to Amazon.com securely, you are not going to drive to Seattle and agree on a shared secret with Amazon then travel back home. This is where "Public Key Cryptography" (nee: Asymmetric encryption) comes in. It allows you to break a "secret" into two parts. One is a mathematical value that when plugged into a function turns a value into a cypher. The other is a value that when plugged into a mathematical function, turns the cypher back into the clear text, but more importantly, it works in reverse as well.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Let's look at this briefly in pseudocode:</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> publicKey = X</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> privateKey = Y</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> cypher: byte[] = encrypt(publicKey, "Hello")</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> message: string = decrypt(privateKey, cypher)</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> </span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> // We encrypted with the public key and decrypted</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> // with the private key</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> message == "Hello"</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> cypher = encrypt(privateKey, "Hello, back at you!");</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> message = decrypt(publicKey, cypher)</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> </span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> // We encrypted with the private key and decrypted</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> // with the public key</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> message == "Hello, back at you!</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c3 c21" style="font-family: "courier new"; font-size: 10pt;"> </span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This means that if I want you to communicate with me securely, I can give you my "Public Key" in the open -- everyone can know it, and know that it is for me -- but if you encrypt a message using my public key, only I can read it. This is the fundamental idea here: You have three components, the algorithm (the encrypt/decrypt functions), two keys (public/private), and we don't need a shared secret. I can make one side of this symmetry public, and you can communicate securely with me. As importantly, you know that if you can decrypt a particular cypher using my public key, it must have come from me.</span></div>
<h2 class="c22" id="h.fk9erk2pqpi6" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">Adding the "Infrastructure" to Public Key Cryptography</span></h2>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Once we have this asymmetric function for securely passing messages to only the intended recipient, or to validate that a message came from a particular recipient, we get into the idea of protocols around these functions. We want to communicate securely between two entities, and validate both ends of the communication. This is where you get the "Diffie-Hellman Key Exchange". It generally works like this…</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<ol>
<li class="c1" style="counter-increment: lst-ctn-kix_1p5gp4eqgddp-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice wants to communicate with Bob.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_1p5gp4eqgddp-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice sends her public key to Bob.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_1p5gp4eqgddp-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Bob sends his public key to Alice.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_1p5gp4eqgddp-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Messaging proceeds:</span></li>
<li class="c26 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c11" style="font-size: 12pt;">When Alice sends a message to Bob she encodes it with </span><span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(message) => encrypt(bobsPublicKey, encrypt(alicesPrivateKey, message))</span></li>
<li class="c8 c26" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c11" style="font-size: 12pt;">Bob decodes the message with </span><span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(cypher) => decrypt(bobsPrivateKey, decrypt(alicesPublicKey, cypher))</span></li>
<li class="c26 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c6" style="font-size: 12pt; vertical-align: baseline;">And vice-versa</span></li>
</ol>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This means that each message passed can firstly only be from the sender, and secondly only be received by the intended recipient. In effect, the stacking of these two functions becomes the shared secret between the parties we discussed above. In practice, this almost never works this way when electrons hit silicon, but we will talk about that in the mathematics section.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">There are some simple obvious problems here. First is the "man in the middle" attack. If Charlie can intercept all of Alice's communications, when the key exchange takes place, he can send his public key to both Alice and Bob during the key exchange, then decrypt both of their messages and re-encrypt them before passing the messages on to the other (If you have ever used the invaluable Charles Proxy tool for development, you have seen this happen -- and you also now understand where the name originates).</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">In order to prevent this, we need a way to establish a trust relationship to the public keys to prevent Charlie from hijacking the communication. This is where "Certificates" come in. You have almost certainly encountered SSL/TLS certificates in the wild.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">All a "certificate" is, is an identity statement and a public key, encrypted with the private key of a trusted third party. Here we will introduce Dave as a third party whom Alice trusts and Bob has a relationship. He will play the role of a "Certificate Authority", or someone who validates that Bob's public key actually came from Bob and not someone pretending to be Bob, like Charlie did above. Let's look at how this works in the most common case of a one-way certificate trust:</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<ol class="c2 lst-kix_ro1fnqs4r385-0 start" start="1" style="counter-reset: lst-ctn-kix_ro1fnqs4r385-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Bob creates a "Certificate Request" in the form "identity: Bob, key: bobsPublicKey".</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Bob sends the certificate request to Dave, who trusts Bob already, so he encrypts the certificate request with his private key.</span></li>
</ol>
<ul class="c2 lst-kix_ro1fnqs4r385-1 start" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c7 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">createCertificate(identity, publicKey) => encrypt(davesPrivateKey, "identity: ${identity}, key: ${publickey")</span></li>
</ul>
<ol class="c2 lst-kix_ro1fnqs4r385-0" start="3" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">And Dave returns the certificate to Bob.</li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice wants to communicate with Bob.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice sends her public key to Bob.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Bob sends his certificate key to Alice.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice decrypts the certificate with Dave's public key, and see's that he says this is definitely "Bob" and there is a public key.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ro1fnqs4r385-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Messaging proceeds:</li>
</ol>
<ul class="c2 lst-kix_ro1fnqs4r385-1 start" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c26 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c11" style="font-size: 12pt;">When Alice sends a message to Bob she encodes it with </span><span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(message) => encrypt(bobsPublicKey, encrypt(alicesPrivateKey, message))</span></li>
<li class="c26 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c11" style="font-size: 12pt;">Bob decodes the message with </span><span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(cypher) => decrypt(bobsPrivateKey, decrypt(alicesPublicKey, cypher))</span></li>
<li class="c26 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 12pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c6" style="font-size: 12pt; vertical-align: baseline;">And vice-versa. This establishes a two-way trust based on a shared secret of these composite keys.</span></li>
</ul>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Now Alice is taking Dave's word for it that messages are coming from Bob. But more importantly, Charlie can't fake the certificate, signed by Dave's private key, and therefore can no longer snoop on the communication because he has control of Alice's communication channel.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This is how most SSL/TLS communication takes place today. However, if Bob would also like to validate Alice's identity, she can also send a certificate, rather than a raw public key, signed by Dave so that Bob knows this is actually Alice.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">The final question to ask is what if Alice doesn't know Dave from Eve? This is where Bob and Dave can provide, rather than a single certificate, a "chain" of certificates. Bob's certificate is signed by Dave, Dave's certificate is signed by Fred, Fred's certificate is signed by Gretta, and Alice trusts Gretta. She can then start by decrypting Fred's certificate with Gretta's to get a public key, then decrypt Dave's certificate with Fred's, until she gets to decrypting Bob's certificate and receives his trusted public key.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This chain of trust is how many things work in the real world, from SSL/TLS communications over TCP, to code signing for the app stores from Google, Apple, Amazon, and Microsoft.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">The final common part of "Public Key Infrastructure" you might encounter is a "Signature". Much like validating that a message comes from a known sender, sometimes you would like the message itself to be public, but you would like to ensure that it was "Signed" (sent by/approved by/etc) a known party. This is done by hashing the message to a shorter, or fixed-length form, then encrypting the hash with the private key of the signatory.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">In this case, if Alice wanted to sign the message, "I agree to pay $100 to Bob" she would do the following:</span></div>
<ol class="c2 lst-kix_yqh70w3jol0c-0 start" start="1" style="counter-reset: lst-ctn-kix_yqh70w3jol0c-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_yqh70w3jol0c-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Alice hashes the message a simple function and encrypts it.</span></li>
</ol>
<div class="c7 c14" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">signedMessage = message + encrypt(alicesPrivateKey, crc128(message))</span></div>
<ol class="c2 lst-kix_yqh70w3jol0c-0" start="2" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_yqh70w3jol0c-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Dave<span class="c4" style="font-size: 11pt; vertical-align: baseline;"> wants to know if the message is valid. He validates the signature with:</span></li>
</ol>
<div class="c7 c14" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">message, signature = split(signedMessage)</span></div>
<div class="c7 c14" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">hash = crc128(message)</span></div>
<div class="c7 c14" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">assert hash == decrypt(alicesPublicKey, signature)</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This makes it very hard for Charlie to alter the message in a way that is still meaningful, but has the same CRC128 code that the message Alice signed has. If he changes the message to "I agree to pay $1000 to Charlie", the CRC128 hash of the message will change, and therefore the assertion about the signature would fail. In effect most of “blockchain” is simply that someone issues a signed action to alter a ledger document, then other parties sign a block of ledger operations, indicating that the network agrees they are all valid and that any future operations can start from the previous signature, rather than hashing the entire history.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Note that CRC128 isn't a secure hashing algorithm, but it is used here because we think it will be familiar to the reader.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Message singing is very common in places where the content of the message is not intended to be secret, but it might be forwarded on from a recipient. Email is the obvious example, but the SOAP/WS-* specifications also include nested payload signing so that as messages, or parts thereof, move through a system their origin can be re-validated at each step.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">The most common place you will encounter PKI, however, will be TLS (or SSL) connections, so we will look at those next.</span></div>
<h2 class="c22" id="h.aratnx50g0ze" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">TLS 1.3</span></h2>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">TLS or Transport Layer Security 1.3 is the latest specification that performs a key exchange over the TCP for two hosts, and is what the "s" usually means in "https://" URLs these days. This is actually a big step forward over the previous SSL (Secure Socket Layer) or TLS specifications because it reduces the number of round trips between the two by about 30%.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">It covers the elements of Diffie-Hellman we discussed above, but covers a larger set of considerations than the most basic examples of key exchange you see above include.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
It begins with the client sending a "Hello" message to the server this looks, again in pseudocode, like this:</div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">{</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "tls-version": 1.3,</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "message": "Hello",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "supported-ciphers": [</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "FooCryptV1.0",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "FooCryptV1.1",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV2.3"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> ],</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key-agreements": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "FooCryptV1.0": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "XXXX",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "certificate-chain": "X1X1X1"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> },</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "FooCryptV1.1": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "YYYY",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "certificate-chain": "Y1Y1Y1"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> },</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV2.3" : {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "ZZZZZ"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> }</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> }</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">}</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Here, supported ciphers are a list of the various implementations of encrypt() and decrypt() the client has available. For each of these, it will also send a "Key Agreement", which is either a simple public key, or a certificate with identity and a public key.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">The server then chooses the cipher that will be used for the rest of the communication. It can do this based on any number of parameters. Maybe it knows that FooCrypt 1.0 has been "broken" and has a vulnerability, so it will never choose that one. Perhaps the server requires clients connecting to it to have a trusted certificate chain, in this case it would eliminate BarCo Secrets 2.3, so "FooCryptV1.1" it is. The server then replies with:</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">{</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "message": "Hello",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "chosen-cipher": "FooCryptV1.1",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key-agreement": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "AAAA",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "certificate-chain": "A1A1A1"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> }</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">}</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">At this point, the two parties have agreed on their cipher algorithm and key, and the next message from the client should be encrypted with the agreed upon keys.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
It might be that the server doesn't like ANY of the client's offerings, though. In this case it would reply to the client with:</div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">{</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "message": "Hello-Retry",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "supported-ciphers": [</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV3.1",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV3.0"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> ],</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key-agreements": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV3.0": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "YYYY",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "certificate-chain": "Y1Y1Y1"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> },</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "BarCoSecretsV3.1": {</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "key": "YYYY",</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> "certificate-chain": "Y1Y1Y1"</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> }</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"> }</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">}</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Maybe the server originally supported "BarCoSecretsV2.3", but the client didn't provide a certificate chain. Maybe it only supports these two algorithms. Either way, the client should now decide whether it can comply with what the server is offering, in which case it will send a "Hello-Retry-Response" message, or it will fail.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">In practice, "Hello-Retry" doesn't happen very often. The list of mainstream cipher suites is pretty well established at this point. Though interestingly, RSA, the cipher suite most people think of when they think of PKI, is no longer supported because it has always had its own key exchange protocol that was slim lined for performance. Rather than use the D-H keys for transport traffic, RSA would use the PKI from each of the two ends to negotiate a true, new shared secret that was only used for the "session" (or life of the TCP connection). This was optimal when most people had very slow connections to the internet, and slow processors, because it kept the data traffic and CPU usage to a minimum. Today very few people are using less than a 128kbaud connection (GPRS mobile or ISDN landline) connection, so reducing the number of round trips for the key exchange is the priority. If you have 100mb throughput, but 150ms latency, sending a number of key options across the wire is less time-expensive than waiting 150ms several times for the message-response cycle.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<h2 class="c22" id="h.ic67vjo78zjc" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">Blockchain</span></h2>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Blockchain is a way to do a distributed transaction log among parties that don’t trust each other. It is built on the fundamental ideas of public key cryptography. So let’s walk through how it works.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Each block in the chain is a set of data that is hashed using a hash function as you have seen before, but in addition to the data in the current block it includes the value of the hash from the previous block. For example:</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span style="font-size: 11pt;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu2lqEg5yUiXeZ4PvMMpAdHg7fZrs6d761Bq2EgiFycYgXd5sdYSn26QtMmTb_yaEYQYPBRUONCPmf42CUbjODpF-ri0cQkQZBth-HEmK6EFaBVN4AFKc6OaRlklRwY0qpHEtOzIP0xOI/s1600/Screen+Shot+2020-06-09+at+11.28.07+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="341" data-original-width="469" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu2lqEg5yUiXeZ4PvMMpAdHg7fZrs6d761Bq2EgiFycYgXd5sdYSn26QtMmTb_yaEYQYPBRUONCPmf42CUbjODpF-ri0cQkQZBth-HEmK6EFaBVN4AFKc6OaRlklRwY0qpHEtOzIP0xOI/s1600/Screen+Shot+2020-06-09+at+11.28.07+AM.png" /></a></div>
<span style="font-size: 11pt;"><br /></span>
<span style="font-size: 11pt;"><br /></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span style="font-size: 11pt;">So now, as each node in the network wants to submit a new block it passes it to the other nodes and they traverse the block change to make sure that the ledger values are accurate, then once a critical mass of nodes accept the new block, the new hash value becomes the head of the linked list to new blocks to be based upon. This means that someone who wants to create a new block doesn’t need to know the full state of the ledger, but only what their “account balance” should be, and the hash value of the previous block in the chain. They can then send a new block containing 1..n transactions for the nodes in the network to agree upon. This can, of course lead to race conditions, where two people are attempting to submit blocks from the same head node. Once one of them is accepted, the ones that didn’t win the race must recompute the hash for their block and resubmit it. More importantly, they need to be able to handle the case that even if they had examined the entire ledger to this point, the transaction might be rejected because the block that won the race has moved a balance into the negative.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"><br />These complexities of implementation as well as the overall computational intensity (read: SLOW) of blockchains should be chosen as a solution very selectively. A traditional transactional database from a central authority (read: bank) will almost always prove faster and more reliable. However, blockchain has a significant number of benefits, including being “publicly auditable”. This makes it a good solution among parties that do not have a trusted central authority.<br /><br />This still, however, isn’t a secure transaction. Why is to prevent Eve from submitting a node that says “Alice pays Eve: $1000”? This is where PKI comes into play. Let’s expand our block data to be a bit larger.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6Ya8MFHz4_HtJikU1KEmV-fIXTJNWkc_nhv0G2B9m8IV8BzeIvc2fAc-7v_P8R3WbN9Z6LrQtAU9R5qJndq8BrUd4RuYf7ezVwSaZAwXid6W6HDRqvXFyaNXfRiwiIKFiD9H6_0Wc45Q/s1600/image1.png" imageanchor="1" style="background-color: white; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="347" data-original-width="624" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6Ya8MFHz4_HtJikU1KEmV-fIXTJNWkc_nhv0G2B9m8IV8BzeIvc2fAc-7v_P8R3WbN9Z6LrQtAU9R5qJndq8BrUd4RuYf7ezVwSaZAwXid6W6HDRqvXFyaNXfRiwiIKFiD9H6_0Wc45Q/s400/image1.png" width="400" /></a></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span style="font-size: 11pt;"><br /></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span style="font-size: 11pt;"><br /></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span style="font-size: 11pt;">Here we have done two things:</span></div>
<ol class="c2 lst-kix_ecf7s6v6hn1-0 start" start="1" style="counter-reset: lst-ctn-kix_ecf7s6v6hn1-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_ecf7s6v6hn1-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">We replaced “Names” in the transaction logs, with key values. As you have seen, we can clearly associate a public key with a specific user of the system.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ecf7s6v6hn1-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">We have signed each message with the private key of the person authorizing the transaction.</span></li>
</ol>
<div class="c5 c33" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This ensures when the nodes are evaluating the block for consistency with the total ledger values, it can simply say “Is the transaction validly signed by the payer’s private key?”, meaning “Does the hash of the message value equal the decrypted value of the signature using the payer’s public key?” If it does, then the transaction is valid. If all the transactions in the block are valid, and the global ledger is balanced, then the block can be accepted.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
You have likely also heard of “BitCoin Mining” this is basically a scheme that allows users to increase their ledger values by finding something that is computationally hard but can be evaluated easily by other nodes. For a simple example, we can use a Mersenne Prime: this is a prime number whose value is 2 to some power minus 1. E.g. 7 = 2<span class="c20" style="vertical-align: super;">3</span>-1 or 31 = 2<span class="c20" style="vertical-align: super;">5</span>-1. There are a large number of known Mersenne primes, but they are computationally intensive to find, as you must take 2 to the next power over the previous and factor the number. However, you can validate a Mersenne prime very quickly using the <span class="c25" style="color: #1155cc; text-decoration-line: underline; text-decoration-skip-ink: none;"><a class="c18" href="https://www.google.com/url?q=https://en.wikipedia.org/wiki/Lucas%25E2%2580%2593Lehmer_primality_test&sa=D&ust=1591719745048000" style="text-decoration: inherit;">Lucas-Lerhmer primality test</a></span> on a number that is clearly 2<span class="c20" style="vertical-align: super;">n</span><span class="c4" style="font-size: 11pt; vertical-align: baseline;">-1. This means someone could post a message to the block chain that says:</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn9NhLVgOcVIv7AWKy0YO3PHVrnlR0CUDZWf5v19YyOdQyb_nh_aQTBcCIqF5rweWr1yMHDqGV_2E8OcW3rPeJDH4r0zWBzb7BzJ94qqCVtAYPQsFG-eo7UYEsYxopizQGhwbuma8M904/s1600/image2.png" imageanchor="1" style="background-color: white; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="207" data-original-width="624" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn9NhLVgOcVIv7AWKy0YO3PHVrnlR0CUDZWf5v19YyOdQyb_nh_aQTBcCIqF5rweWr1yMHDqGV_2E8OcW3rPeJDH4r0zWBzb7BzJ94qqCVtAYPQsFG-eo7UYEsYxopizQGhwbuma8M904/s400/image2.png" width="400" /></a></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<br /></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Then when nodes are validating the block, they say “Is 31 a Mersenne prime AND has no one else discovered it in a previous block?” If the answers to both questions are “yes”, then Alice’s account is credited with $100, or 1 BitCoin, or whatever other unit the network agrees is the value of the discovery.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">This is a simplistic example of “mining” a cryptocurrency, but next we will look at a simplistic example of the entire toolchain.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<h2 class="c22" id="h.n67y09707fu2" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">Prime Numbers and Public Key Cryptography</span></h2>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">How does this actually work? Well, it works by using large prime numbers to do math that are hard to guess from the message content, because factoring very large numbers (outside of a large quantum computer) is exceedingly time intensive. We can then use the modulo of the composition of these primes to encode and decode values.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
First, to create a private key, we need two prime numbers:</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">p = 5</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">q = 11</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Next, we find the “modulus number” between the two, this is simply the product, but we will use this in mod operations later:</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">m = p * q</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(55)</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Next we need to find a number that is not related to either of these primes... This is easy to do by just subtracting from each of them and multiplying:</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">fn = (p - 1) * (q -1)</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(40)</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Now we need any number that is relatively prime to fn and less than it. Relatively prime just means they share no common factors. 40 has the factors 2, and 5, so we could use any of 3, 7, 9, 11, 13, 17, 19, 21, 23, 27, 29, 31, 33, 37, and 39. Doesn't matter which, but let's choose 7.</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">public_encrypt_exponent = 7</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Now my "public key" that I can share with the world are the numbers 7 and 55. Now I need a "private key". This is again two numbers with our base modulus number, and a new exponent in the form:</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">private_decrypt_exponent = public_encrypt_exponent^-1 % fn</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(23)</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">My private key is now my private decrypt exponent, and the modulus of my two original numbers, or (23, 55).</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Now if I want to encrypt the value 50 for the owner of the private key (note, the value HAS to be below the value of the modulus, so I can't use 60. Remember, usually these are very large numbers):</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">cyper = 50 ^ (public_encrypt_exponent) % m</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(30)</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Now I want to decrypt the value:</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">message = 30 ^ (private_decrypt_exponent) % m</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">(50)</span></div>
<div class="c16" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.45; padding-bottom: 12pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
The important thing here, though, is that the wrapping of functions DOESN'T have to be done separately. We know we want to decrypt with our private key and decrypt with their public key all the time, we can actually stack these operations into more efficient mathematical operations.</div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c0" style="font-family: "courier new"; font-size: 10pt; vertical-align: baseline;">message = cypher ^ (my_private_exponent * their_public_exponent) % (my_m + their_m)</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c3 c21" style="font-family: "courier new"; font-size: 10pt;"><br /></span>Ob<span class="c4" style="font-size: 11pt; vertical-align: baseline;">viously there is more to it than just this. If this was all there was, there wouldn’t be a selection of ciphers from which to choose, but at a fundamental level, the mathematical operations you see above is how they all work.</span></div>
<h2 class="c22" id="h.o6v47wn8cc9o" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
Things to Know about Your Organization and Project</h2>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">While we are not getting into tooling here there are some things you might want to ask yourself about your organization and or project:</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<ol class="c2 lst-kix_bh43gstzgj9u-0 start" start="1" style="counter-reset: lst-ctn-kix_bh43gstzgj9u-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_bh43gstzgj9u-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Does my organization have a centralized certificate authority, or are certificates requested one off from a global certificate authority?</span></li>
</ol>
<ul class="c2 lst-kix_5shrmeln1ugo-0 start" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c7 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Is that a certificate authority certified by one of the global certificate authorities, or is it only in my company?</span></li>
<li class="c7 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">If it is only in my company, what do I need to do to make sure my chosen language/library/runtime platform can trust the certificates my company is issuing?</span></li>
</ul>
<ol class="c2 lst-kix_f49hq1r6av6k-0 start" start="1" style="counter-reset: lst-ctn-kix_f49hq1r6av6k-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_f49hq1r6av6k-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Certificates in the real world have an expiration date. How are we managing expiration, and are their processes that audit my running code to make sure to alert someone if a certificate is about to expire?</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_f49hq1r6av6k-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Certificates in the real world come in two general flavors: those that identify a host, and those that identify a host and a business entity.</span></li>
</ol>
<ul class="c2 lst-kix_s1j2gy464x2x-0 start" style="list-style-type: none; margin: 0px; padding: 0px;">
<li class="c7 c8" style="font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 72pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Is it important for my organization that customers see that a certificate is bound to a business entity? (This is the difference between something like LetsEncrypt.org/certbot and getting a "real" certificate from Thawte or Verisign).</span></li>
</ul>
<ol class="c2 lst-kix_bgrxy9nm2lxl-0 start" start="1" style="counter-reset: lst-ctn-kix_bgrxy9nm2lxl-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_bgrxy9nm2lxl-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Finally, do I know how to trust a new certificate authority and create or sign certificate requests within the context of my chosen platform/runtime/framework/http library?</li>
</ol>
<h2 class="c22" id="h.1l17zkxg0q3u" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">Trusting a new Certificate Authority</span></h2>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Whether your organization has a managed certificate authority, or you need to trust a non-authoritative certificate for development purposes, i.e. a self-signed certificate for localhost, you should know how to do this out of hand on whatever your environment is.</div>
<h3 class="c29" id="h.lggay0ci04ts" style="break-after: avoid; color: #434343; font-family: Arial; font-size: 14pt; line-height: 1.15; padding-bottom: 4pt; padding-top: 16pt;">
Debian/<span class="c9" style="font-size: 14pt; font-weight: 400; vertical-align: baseline;">Ubuntu Linux</span></h3>
<ol class="c2 lst-kix_ox2xufcc30gn-0 start" start="1" style="counter-reset: lst-ctn-kix_ox2xufcc30gn-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_ox2xufcc30gn-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Create a directory in <span class="c11 c30" style="background-color: white; color: #222222; font-family: "roboto"; font-size: 12pt;"> </span><span class="c3" style="font-family: "courier new";">/usr/local/share/ca-certificates/</span><span class="c4" style="font-size: 11pt; vertical-align: baseline;"> for your organization</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ox2xufcc30gn-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Place the certificate file (this is the file that looks like a Base64 encoded value with delimiters) in the directory.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ox2xufcc30gn-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c3" style="font-family: "courier new";">chmod</span><span class="c4" style="font-size: 11pt; vertical-align: baseline;"> the directory to 755 and 644 for the certificate file.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_ox2xufcc30gn-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Run <span class="c3" style="font-family: "courier new";">sudo update-ca-certificates</span></li>
</ol>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<h3 class="c29" id="h.x7gajhppn4wu" style="break-after: avoid; color: #434343; font-family: Arial; font-size: 14pt; line-height: 1.15; padding-bottom: 4pt; padding-top: 16pt;">
<span class="c9" style="font-size: 14pt; font-weight: 400; vertical-align: baseline;">MacOS</span></h3>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<ol class="c2 lst-kix_r9bdmwgo1k3p-0 start" start="1" style="counter-reset: lst-ctn-kix_r9bdmwgo1k3p-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_r9bdmwgo1k3p-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;">Open <span class="c3" style="font-family: "courier new";">Keychain Access</span> from <span class="c3 c19" style="font-family: "courier new"; font-size: 11pt; vertical-align: baseline;">/Applications/Utilities</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_r9bdmwgo1k3p-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Select “Login” or “System” from the right, depending on whether this is for a single user, or system wide.</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_r9bdmwgo1k3p-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Drag the certificate file into the list of keychain items.</span></li>
</ol>
<h3 class="c29" id="h.3p5qjr3azskh" style="break-after: avoid; color: #434343; font-family: Arial; font-size: 14pt; line-height: 1.15; padding-bottom: 4pt; padding-top: 16pt;">
<span class="c9" style="font-size: 14pt; font-weight: 400; vertical-align: baseline;">Windows</span></h3>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<ol class="c2 lst-kix_df8gcd1zh42w-0 start" start="1" style="counter-reset: lst-ctn-kix_df8gcd1zh42w-0 0; list-style-type: none; margin: 0px; padding: 0px;">
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Select Start -> Run -> MMC</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Select File -> Add/Remove Snap In</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Double click “Certificates”</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Select account or Local Computer</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Click Add (+) on Certificates -> Personal</span></li>
<li class="c1" style="counter-increment: lst-ctn-kix_df8gcd1zh42w-0 1; font-family: Arial; font-size: 11pt; line-height: 1.15; margin-left: 36pt; padding-bottom: 0pt; padding-left: 0pt; padding-top: 0pt; text-align: left;"><span class="c4" style="font-size: 11pt; vertical-align: baseline;">Right click on “Certificates” and select “Import”</span></li>
</ol>
<h3 class="c29" id="h.5ffe0xom4ppl" style="break-after: avoid; color: #434343; font-family: Arial; font-size: 14pt; line-height: 1.15; padding-bottom: 4pt; padding-top: 16pt;">
<span class="c9" style="font-size: 14pt; font-weight: 400; vertical-align: baseline;">Java</span></h3>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Java has its own certificate management. On Windows, you can trust the operating system certificate store above by passing the system property on the command line..</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c3" style="font-family: "courier new";">-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT</span><br />
<br />
Most of the time, however, you need to add a certificate to the default keystore. This is in the <span class="c3" style="font-family: "courier new";">$JAVA_HOME/jre/lib/security/cacerts</span> keystore.<br />
<br />
You can add a new CA certificate by running:<br />
<span class="c3" style="font-family: "courier new";">keytool -importcert -trustcacerts -alias some_alias -file /path/to/cert -keystore $JAVA_HOME/jre/lib/security/cacerts</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c24 c3 c21" style="color: #242729; font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c3 c21 c24" style="color: #242729; font-family: "courier new"; font-size: 10pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
When prompted for a keystore password, use “<span class="c3" style="font-family: "courier new";">changeit</span><span class="c4" style="font-size: 11pt; vertical-align: baseline;">”, without the quotation marks. Pro tip: don’t change it.</span></div>
<h2 class="c22" id="h.hp2gxmt1ihlj" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">SSH and Git</span></h2>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
The other most common way you will interact with PKI is through SSH or Git over SSH. On pretty much any computer you use, you will have an <span class="c3" style="font-family: "courier new";">~/.ssh</span> folder. This will contain a file called <span class="c3" style="font-family: "courier new";">id_rsa</span> which is an RSA private key, and <span class="c3" style="font-family: "courier new";">id_rsa.pub</span><span class="c4" style="font-size: 11pt; vertical-align: baseline;"> which is the public key for the private key.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
If you wish to connect to a server in a trusted way, you can add the contents of <span class="c3" style="font-family: "courier new";">id_rsa.pub</span> to the file <span class="c3" style="font-family: "courier new";">~/.ssh/authorized_keys</span> for a user on the server. Then when you SSH to that server, it will validate your local <span class="c3" style="font-family: "courier new";">id_rsa</span> file against that public key and let you connect without a password challenge.<br />
<br />
More importantly, you can use this to authenticate with Git over SSH URLs. For GitHub, you can go to your <span class="c25" style="color: #1155cc; text-decoration-line: underline; text-decoration-skip-ink: none;"><a class="c18" href="https://www.google.com/url?q=https://github.com/settings/ssh/new&sa=D&ust=1591719745063000" style="text-decoration: inherit;">GPG and SSH keys settings and create a new key</a></span>. There you can paste in the contents of your <span class="c3" style="font-family: "courier new";">id_rsa.pub</span> file. Then when you clone a repository and use the <span class="c3" style="font-family: "courier new";">git@github.com</span><span class="c3" style="font-family: "courier new";">:account/repository.git</span> <span class="c4" style="font-size: 11pt; vertical-align: baseline;">format, you will authenticate with your SSH key and skip the password challenge required with HTTPS.</span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;">Somewhere in your user settings for any Git repository manager (GitLab, BitBucket) there is a similar function. As importantly, though, SSH keys can be distributed as secrets in offline manners between teammates, across computers, or to build servers.</span></div>
<h2 class="c22" id="h.xp2ye6q5agdq" style="break-after: avoid; font-family: Arial; font-size: 16pt; line-height: 1.15; padding-bottom: 6pt; padding-top: 18pt;">
<span class="c12" style="font-size: 16pt; font-weight: 400; vertical-align: baseline;">Conclusion and Further Reading</span></h2>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
I hope you have found this introduction useful. If you would like to study further, there is no better source than <span class="c25" style="color: #1155cc; text-decoration-line: underline; text-decoration-skip-ink: none;"><a class="c18" href="https://www.google.com/url?q=https://en.wikipedia.org/wiki/Special:BookSources/0-471-11709-9&sa=D&ust=1591719745065000" style="text-decoration: inherit;">“Applied Cryptography: Protocols, Algorithms, and Source Code in C” by Bruce Schneier</a></span><span class="c4" style="font-size: 11pt; vertical-align: baseline;">. If you weren’t taught with this as a text in school, you would do yourself a disservice as a developer by not reading it.</span></div>
<div class="c5" style="font-family: Arial; font-size: 11pt; height: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
<span class="c4" style="font-size: 11pt; vertical-align: baseline;"></span></div>
<div class="c7" style="font-family: Arial; font-size: 11pt; line-height: 1.15; padding-bottom: 0pt; padding-top: 0pt;">
Also it is worth noting that PKI is not the only type of cryptography you might want to leverage. <span class="c25" style="color: #1155cc; text-decoration-line: underline; text-decoration-skip-ink: none;"><a class="c18" href="https://www.google.com/url?q=https://en.wikipedia.org/wiki/Format-preserving_encryption&sa=D&ust=1591719745065000" style="text-decoration: inherit;">Format Preserving Encryption</a></span> is a means of encoding values using a single key that preserves the general format of the data and is useful for “encryption at rest” in databases. <span class="c25" style="color: #1155cc; text-decoration-line: underline; text-decoration-skip-ink: none;"><a class="c18" href="https://www.google.com/url?q=https://en.wikipedia.org/wiki/Homomorphic_encryption&sa=D&ust=1591719745066000" style="text-decoration: inherit;">Homomorphic Encryption</a></span> encrypts values (especially numeric values) in a way that ensures that relative operations between them, such as comparison, addition, multiplication, result in values that are themselves encrypted with the same key, allowing you to perform computation on encrypted data without ever having to part of the trusted readers of the values.</div>
Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-79147088272489589972018-10-02T19:02:00.001-07:002018-10-02T19:15:11.914-07:00Executors and Futures in JavaThis is part of an experiment. It is "code as blog". This entire blog post is just documented Java code.<br /><br />
<pre style='text-align: left; line-height: 18px; padding: 15px; font-size: 10px; font-family:'Courier New', Courier, monospace; overflow: auto;'><span style='font-weight:bold;color:#7B0052;'>package</span> software.coop.know.future;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.ArrayList;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.Arrays;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.List;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.ArrayBlockingQueue;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.ExecutionException;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.ExecutorService;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.Executors;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.ForkJoinPool;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.Future;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.ThreadPoolExecutor;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.TimeUnit;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.concurrent.atomic.AtomicInteger;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.stream.Collectors;
<span style='font-weight:bold;color:#7B0052;'>import</span> java.util.stream.DoubleStream;
<span style='color:#0F0'>/**
* In this class, we will look at the most common way to interact with Futures -- via executors.
*/</span>
<span style='font-weight:bold;color:#7B0052;'>public</span> <span style='font-weight:bold;color:#7B0052;'>class</span> FuturesWithExecutors <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>public</span> <span style='font-weight:bold;color:#7B0052;'>static</span> <span style='font-weight:bold;color:#7B0052;'>void</span> main(String... args) <span style='font-weight:bold;color:#7B0052;'>throws</span> Exception <span style='font-weight:bold;color:#D3171B'>{</span>
doExecutorService();
doFutures();
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='color:#0F0'>/** This is just a utility method to sleep without a checked exception.
*
* @param ms Number of milliseconds to sleep.
*/</span>
<span style='font-weight:bold;color:#7B0052;'>private</span> <span style='font-weight:bold;color:#7B0052;'>static</span> <span style='font-weight:bold;color:#7B0052;'>void</span> sleepWithoutException(<span style='font-weight:bold;color:#7B0052;'>long</span> ms) <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>try</span> <span style='font-weight:bold;color:#D3171B'>{</span>
Thread.sleep(ms);
<span style='font-weight:bold;color:#D3171B'>}</span> <span style='font-weight:bold;color:#7B0052;'>catch</span> (InterruptedException e) <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>throw</span> <span style='font-weight:bold;color:#7B0052;'>new</span> RuntimeException(e);
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='color:#0F0'>/** A look at the ExecutorService class and how it is used...
*
* @throws InterruptedException
*/</span>
<span style='font-weight:bold;color:#7B0052;'>private</span> <span style='font-weight:bold;color:#7B0052;'>static</span> <span style='font-weight:bold;color:#7B0052;'>void</span> doExecutorService() <span style='font-weight:bold;color:#7B0052;'>throws</span> InterruptedException <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='color:#3F7F5F'>// An ExecutorService is a service that does work off the thread you call it from. They come in many forms, but
</span> <span style='color:#3F7F5F'>// generally they have a pool of threads that pull units of work off a queue, execute them, then pull the next
</span> <span style='color:#3F7F5F'>// one.
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// There is also the the Executors class, which has some utility methods for quickly creating executor services.
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// Let's start with the dead simple example...
</span>
ExecutorService executorService = Executors.newSingleThreadExecutor();
<span style='color:#3F7F5F'>// This created an executor service with a single thread to do work. So if we do...
</span>
System.out.println(<span style='color:#2A00FF'>"Submitting Job 1 from "</span> + Thread.currentThread().getName());
executorService.submit(() -> <span style='font-weight:bold;color:#D3171B'>{</span>
System.out.println(<span style='color:#2A00FF'>"Starting Job 1 on "</span> + Thread.currentThread().getName());
sleepWithoutException(2000);
System.out.println(<span style='color:#2A00FF'>"Finishing Job 1"</span>);
<span style='font-weight:bold;color:#D3171B'>}</span>);
System.out.println(<span style='color:#2A00FF'>"Submitting Job 2 from "</span> + Thread.currentThread().getName());
executorService.submit(() -> <span style='font-weight:bold;color:#D3171B'>{</span>
System.out.println(<span style='color:#2A00FF'>"Starting Job 2 on "</span> + Thread.currentThread().getName());
sleepWithoutException(2000);
System.out.println(<span style='color:#2A00FF'>"Finishing Job 2"</span>);
<span style='font-weight:bold;color:#D3171B'>}</span>);
System.out.println(<span style='color:#2A00FF'>"Submitted Job 2"</span>);
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
System.out.println(<span style='color:#2A00FF'>"---------------------------------------------------------------------------------"</span>);
<span style='color:#3F7F5F'>// This will give us the following output :
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// Submitting Job 1 from main // #1 into the
</span> <span style='color:#3F7F5F'>// Submitting Job 2 from main // #1 is finished submitting
</span> <span style='color:#3F7F5F'>// Starting Job 1 on pool-1-thread-1 // #1 begins running
</span> <span style='color:#3F7F5F'>// Submitted Job 2 // Since #1 is out of the queue and running, submit() for #2 completes
</span> <span style='color:#3F7F5F'>// Finishing Job 1 // #1 finishes
</span> <span style='color:#3F7F5F'>// Starting Job 2 on pool-1-thread-1 // #2 begins running
</span> <span style='color:#3F7F5F'>// Finishing Job 2 // #2 finishes
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// Now we have to do shutdown() and awaitTermination() to prevent the JVM from just shutting down on us. The
</span> <span style='color:#3F7F5F'>// thread in the Executor is a daemon thread, which means it won't prevent the JVM from terminating when "main"
</span> <span style='color:#3F7F5F'>// is done.
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// shutdown() tells the Executor to stop accepting new work.
</span> <span style='color:#3F7F5F'>// awaitTermination() waits for a given amount of time, blockingly, until all the jobs that are in the queue
</span> <span style='color:#3F7F5F'>// have finished.
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// This was perhaps the simplest example possible. Now lets look at perhaps the most complex...
</span>
<span style='font-weight:bold;color:#7B0052;'>final</span> AtomicInteger index = <span style='font-weight:bold;color:#7B0052;'>new</span> AtomicInteger(0);
executorService = <span style='font-weight:bold;color:#7B0052;'>new</span> ThreadPoolExecutor(
1, <span style='color:#3F7F5F'>// a minimum number of threads.
</span> 5, <span style='color:#3F7F5F'>// a maximum number of threads
</span> 2, TimeUnit.SECONDS, <span style='color:#3F7F5F'>// a time to wait before growing the pool
</span> <span style='font-weight:bold;color:#7B0052;'>new</span> ArrayBlockingQueue<>(10), <span style='color:#3F7F5F'>// queue of tasks
</span> r -> <span style='font-weight:bold;color:#D3171B'>{</span> <span style='color:#3F7F5F'>// a custom ThreadFactory
</span> <span style='font-weight:bold;color:#7B0052;'>int</span> thread = index.getAndIncrement();
System.out.println(<span style='color:#2A00FF'>"Creating thread "</span>+thread);
Thread t = <span style='font-weight:bold;color:#7B0052;'>new</span> Thread(r);
t.setName(<span style='color:#2A00FF'>"Custom Thread "</span> + thread);
t.setDaemon(<span style='font-weight:bold;color:#7B0052;'>true</span>);
<span style='font-weight:bold;color:#7B0052;'>return</span> t;
<span style='font-weight:bold;color:#D3171B'>}</span>,
<span style='font-weight:bold;color:#7B0052;'>new</span> ThreadPoolExecutor.CallerRunsPolicy() <span style='color:#3F7F5F'>// A policy for jobs that are rejected from the queue
</span> <span style='color:#3F7F5F'>// "CallerRunsPolicy" means that if you can't accept a new
</span> <span style='color:#3F7F5F'>// task, run it immediately on the calling thread.
</span>
);
<span style='font-weight:bold;color:#7B0052;'>for</span> (<span style='font-weight:bold;color:#7B0052;'>int</span> i = 0; i < 40; i++) <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>final</span> <span style='font-weight:bold;color:#7B0052;'>int</span> idx = i;
executorService.submit(
() -> <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>long</span> runtime = 1900 + Math.round(Math.random() * 200D); <span style='color:#3F7F5F'>// sleep for random time.
</span> System.out.println(<span style='color:#2A00FF'>"Starting "</span> + idx + <span style='color:#2A00FF'>" for "</span> + runtime + <span style='color:#2A00FF'>" ms on "</span>
+ Thread.currentThread().getName());
sleepWithoutException(runtime);
System.out.println(<span style='color:#2A00FF'>"Finishing "</span> + idx);
<span style='font-weight:bold;color:#D3171B'>}</span>
);
sleepWithoutException(100);
<span style='font-weight:bold;color:#D3171B'>}</span>
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
System.out.println(<span style='color:#2A00FF'>"---------------------------------------------------------------------------------"</span>);
<span style='color:#3F7F5F'>// This gives us output akin to the following...
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// Creating thread 0 < create the first thread
</span> <span style='color:#3F7F5F'>// Starting 0 for 1986 ms on Custom Thread 0 < start task
</span> <span style='color:#3F7F5F'>// Creating thread 1 < grow the thread bool.
</span> <span style='color:#3F7F5F'>// Starting 11 for 1928 ms on Custom Thread 1 < start the next task. Notice this ISN'T #1, it is the first job
</span> <span style='color:#3F7F5F'>// that won't fit in the queue
</span> <span style='color:#3F7F5F'>// Creating thread 2 < grow again.
</span> <span style='color:#3F7F5F'>// Starting 12 for 2010 ms on Custom Thread 2
</span> <span style='color:#3F7F5F'>// Creating thread 3
</span> <span style='color:#3F7F5F'>// Starting 13 for 2001 ms on Custom Thread 3
</span> <span style='color:#3F7F5F'>// Creating thread 4 < Max thread pool size
</span> <span style='color:#3F7F5F'>// Starting 14 for 2074 ms on Custom Thread 4
</span> <span style='color:#3F7F5F'>// Starting 15 for 1999 ms on main < Since we are now at max threads, and the queue is full,
</span> <span style='color:#3F7F5F'>// job 15 executes on the "main" thread inline with our our call
</span> <span style='color:#3F7F5F'>// to submit it.
</span> <span style='color:#3F7F5F'>// Finishing 0
</span> <span style='color:#3F7F5F'>// Starting 1 for 2042 ms on Custom Thread 0 < We just now pull the second job off the queue
</span> <span style='color:#3F7F5F'>// Finishing 11
</span> <span style='color:#3F7F5F'>// Starting 2 for 1993 ms on Custom Thread 1
</span>
<span style='color:#3F7F5F'>// As you can see, jobs are not necessarily executed in a FIFO manner, especially if you have a variable sized
</span> <span style='color:#3F7F5F'>// thread pool.
</span> <span style='font-weight:bold;color:#D3171B'>}</span>
<span style='color:#0F0'>/** Using Futures with Executors
*
*/</span>
<span style='font-weight:bold;color:#7B0052;'>private</span> <span style='font-weight:bold;color:#7B0052;'>static</span> <span style='font-weight:bold;color:#7B0052;'>void</span> doFutures() <span style='font-weight:bold;color:#7B0052;'>throws</span> InterruptedException <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='color:#3F7F5F'>// In the previous example, we looked entirely at submitting "Runnables" to our ExecutorService. But sometimes,
</span> <span style='color:#3F7F5F'>// you want to get a result back from a task running off thread. Let's look at that.
</span> System.out.println(<span style='color:#2A00FF'>"doFutures() ---------------------------------------------------------------------"</span>);
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Double> doubles = Arrays.asList( 0D, 1D, 2D, 3D, 4D, 5D);
List<Future<String>> futures = doubles.stream()
.map(d-> executorService.submit(()-><span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>long</span> runtime = Math.round(Math.random() * 2000D);
System.out.println(<span style='color:#2A00FF'>"Running on "</span>+Thread.currentThread().getName()+ <span style='color:#2A00FF'>" for "</span>+runtime);
sleepWithoutException(runtime);
<span style='font-weight:bold;color:#7B0052;'>return</span> Double.toString(d * Math.PI) +<span style='color:#2A00FF'>" from "</span>+Thread.currentThread().getName();
<span style='font-weight:bold;color:#D3171B'>}</span>)
).collect(Collectors.toList());
futures.forEach(future -> <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>try</span> <span style='font-weight:bold;color:#D3171B'>{</span>
System.out.println(future.get());
<span style='font-weight:bold;color:#D3171B'>}</span> <span style='font-weight:bold;color:#7B0052;'>catch</span> (ExecutionException |InterruptedException e) <span style='font-weight:bold;color:#D3171B'>{</span>
e.printStackTrace();
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='font-weight:bold;color:#D3171B'>}</span>);
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
System.out.println(<span style='color:#2A00FF'>"---------------------------------------------------------------------------------"</span>);
<span style='color:#3F7F5F'>// This gives us the output:
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-2 for 695
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-1 for 173
</span> <span style='color:#3F7F5F'>// 0.0 from pool-1-thread-1
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-1 for 1135
</span> <span style='color:#3F7F5F'>// 3.141592653589793 from pool-1-thread-2
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-2 for 915
</span> <span style='color:#3F7F5F'>// 6.283185307179586 from pool-1-thread-1
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-1 for 316
</span> <span style='color:#3F7F5F'>// 9.42477796076938 from pool-1-thread-2
</span> <span style='color:#3F7F5F'>// Running on pool-1-thread-2 for 409
</span> <span style='color:#3F7F5F'>// 12.566370614359172 from pool-1-thread-1
</span> <span style='color:#3F7F5F'>// 15.707963267948966 from pool-1-thread-2
</span>
<span style='color:#3F7F5F'>// You can see that this is obviously in order from our list of Doubles, but it is also "As Fast As Possible"
</span> <span style='color:#3F7F5F'>// with two threads. Why? Because despite the fact that our execution time varies wildly, we iterate over the
</span> <span style='color:#3F7F5F'>// mapped Futures in order. That a job down the queue finished before a previous one doesn't stop the
</span> <span style='color:#3F7F5F'>// ExecutorService from continuing to run. The value of the Callable is contained in the Future. So if a later
</span> <span style='color:#3F7F5F'>// one finished before the one we are waiting on, it is just a long pole small pole problem.
</span>
<span style='color:#3F7F5F'>// In all of the examples so far, we have created an ExcecutorService to control threads, or queue size or
</span> <span style='color:#3F7F5F'>// whatever. Java does have a default one we can use that should have some reasonable defaults:
</span> <span style='color:#3F7F5F'>// The ForkJoinPool.
</span>
<span style='color:#3F7F5F'>// The ForkJoinPool is used when you use language-level parallelism. For example:
</span>
DoubleStream.of(1D, 2D, 3D, 4D, 5D).parallel()
.forEach(d-> <span style='font-weight:bold;color:#D3171B'>{</span>
sleepWithoutException(100);
System.out.println( d + <span style='color:#2A00FF'>" from "</span>+Thread.currentThread().getName());
<span style='font-weight:bold;color:#D3171B'>}</span>);
System.out.println(<span style='color:#2A00FF'>"---------------------------------------------------------------------------------"</span>);
<span style='color:#3F7F5F'>// This gives us something like:
</span> <span style='color:#3F7F5F'>//
</span> <span style='color:#3F7F5F'>// 5.0 from ForkJoinPool.commonPool-worker-2
</span> <span style='color:#3F7F5F'>// 2.0 from ForkJoinPool.commonPool-worker-1
</span> <span style='color:#3F7F5F'>// 4.0 from ForkJoinPool.commonPool-worker-4
</span> <span style='color:#3F7F5F'>// 3.0 from main
</span> <span style='color:#3F7F5F'>// 1.0 from ForkJoinPool.commonPool-worker-3
</span>
<span style='color:#3F7F5F'>// 3.0 on Main? Why? Who knows. This is Java making a guess about the pool size based on the number of cores on
</span> <span style='color:#3F7F5F'>// my machine (8) and whatever other heuristic it uses.
</span>
<span style='color:#3F7F5F'>// The important think here is you can get at this "generic" executor service the same way .parallel() does...
</span>
ForkJoinPool forkJoin = ForkJoinPool.commonPool();
List<Future<Double>> futureDoubles = <span style='font-weight:bold;color:#7B0052;'>new</span> ArrayList<>(20);
<span style='font-weight:bold;color:#7B0052;'>for</span>(<span style='font-weight:bold;color:#7B0052;'>double</span> d = 0; d < 20D; d++) <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>double</span> finalD = d;
futureDoubles.add(forkJoin.submit(() -> <span style='font-weight:bold;color:#D3171B'>{</span>
sleepWithoutException(2000);
System.out.println(<span style='color:#2A00FF'>"Computing on "</span> + Thread.currentThread().getName());
<span style='font-weight:bold;color:#7B0052;'>return</span> finalD * Math.PI;
<span style='font-weight:bold;color:#D3171B'>}</span>));
<span style='font-weight:bold;color:#D3171B'>}</span>
futureDoubles.forEach(f-> <span style='font-weight:bold;color:#D3171B'>{</span>
<span style='font-weight:bold;color:#7B0052;'>try</span> <span style='font-weight:bold;color:#D3171B'>{</span>
System.out.println(f.get());
<span style='font-weight:bold;color:#D3171B'>}</span> <span style='font-weight:bold;color:#7B0052;'>catch</span> (ExecutionException|InterruptedException e) <span style='font-weight:bold;color:#D3171B'>{</span>
e.printStackTrace();
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='font-weight:bold;color:#D3171B'>}</span>);
System.out.println(<span style='color:#2A00FF'>"---------------------------------------------------------------------------------"</span>);
<span style='color:#3F7F5F'>// This gives us something like:
</span>
<span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-5
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-6
</span> <span style='color:#3F7F5F'>// 0.0
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-4
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-2
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-3
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-1
</span> <span style='color:#3F7F5F'>// Computing on ForkJoinPool.commonPool-worker-7
</span> <span style='color:#3F7F5F'>// 3.141592653589793
</span> <span style='color:#3F7F5F'>// 6.283185307179586
</span> <span style='color:#3F7F5F'>// 9.42477796076938
</span>
<span style='font-weight:bold;color:#D3171B'>}</span>
<span style='font-weight:bold;color:#D3171B'>}</span></pre>Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-10306129658960584332018-08-29T15:16:00.001-07:002018-08-29T15:16:47.354-07:00"Unit Testing" and Third Party SoftwareIt is legit not my intention to make this a "testing" blog, but as I started this, I found myself for the first time in a testing role, so this is stuff at the top of mind. One thing I want to talk about, though, is "What is 'Unit Testing'?"<br />
<br />
So one of the prime directives from the "Unit Testing" world is "Don't test software that isn't yours". This is a fine idea but there is are trap around it into which you don't want to fall. One specifically I want to discuss here:<br />
<br />
Your configuration information IS YOUR SOFTWARE.<br />
<br />
Let's pick an easy example: Hibernate. If you are building Java software, some form of JPA, and probably Hibernate is in your stack.<br />
<br />
So lets talk about queries. Maybe you are using something with a dynamic proxy system. Maybe you are using compiled queries directly with your <span style="font-family: "courier new" , "courier" , monospace;">EntityManager</span>. Doesn't matter. Your <b>ANNOTATIONS</b> are code, and should be tested.<br />
<br />
Do you have to test the dynamic proxy generation? No. But if you have a DAO that looks like:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />@Query("SELECT o FROM Foo WHERE o.value like '%:bar%')</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">List<Foo> fooValuesWithBar(String bar)</span><br />
<br />
Should you be writing unit tests around whether the dynamic proxy correctly interprets your query? No. "Noy my yob mah." But making sure that all the configuration information in the annotation you wrote is correct <b>is</b> your job. If you are not writing a unit test that covers the <b>annotation</b> as code, you don't really have coverage.<br />
<br />
The long and the short of this, is if you are using a tool to dynamically generate DAOs and your unit tests aren't going all the way to the database, you aren't actually covering your code, because the metadata about how the DAO framework will construct your queries <b>is your code</b>. Again, let's consider the unit test you should have around <span style="font-family: "courier new" , "courier" , monospace;">fooValuesWithBar()</span>... If you insert a stray character into the <span style="font-family: "courier new" , "courier" , monospace;">@Query</span>, then your unit test should fail. The fact that you aren't writing the actual implementation of <span style="font-family: "courier new" , "courier" , monospace;">fooValuesWithBar()</span> on this interface doesn't matter. You have defined the functionality with the annotation, so you need a test around it. The annotation is code.<br />
<br />
So let's not just bitch about it, let's solve some problems.<br />
<br />
So if you are using Hibernate/TopLink/EclipseLink, your code <b>should</b> be database portable. Is it? Do you care if it is not? At my current gig we are using Flyway as part of Spring Boot to do database migrations, but that involves writing SQL files. As soon as you get into writing SQL files, you have given up on DB portability. That said, the other option is trusting the JPA provider to update your schema. As much as people SAY that is a thing that can happen, I personally don't trust it.<br />
<br />
That said, for the purposes of unit tests, there is no reason you can't rely on your JPA provider to create a schema it thinks is reasonable. That is, you can write DAO/Entity tests against in-memory Hypersonic/Derby/JavaDB and feel those are good tests. Database migration with a tool like Flyway can still be a thing, but you can pass that off to an "integration test" without feeling like you have lost something... mostly.<br />
<br />
So let's go with some rules:<br />
<br />
<br />
<ol>
<li>Don't mock a DAO unless you REALLY know what you are doing. Mocking things that are loaded with configuration is, IMHO, fraught. Does your test provide value? Well, that assumes the things you are mocking comply with production systems. Mocking an external service for which you have a contract test is OK. Mocking a DAO/Service/Other Dynamic Proxy where you aren't sure your annotations are correct?</li>
<li>Use your DAO to persist and read outside of your test, rather than use verify calls. Something in a database is real. <span style="font-family: "courier new" , "courier" , monospace;">save(any(Foo.class))</span> is a crutch. Create a transient database if you need to.</li>
<li>This doesn't just apply to DAOs. Anything with Annotation-specified behavior should be unit tested. This means custom XML/JSON (de)serialization rules, too.</li>
</ol>
Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-13886781270545905842018-08-29T15:11:00.002-07:002018-08-29T15:31:33.629-07:00Quick Tip: Images in React-Native on Android Not LoadingSo something I ran into recently that I never found any good tips around.<br />
<br />
We had a problem with static asset images not painting on Android. It appears that if there is a state-triggered repaint while the image is being spun up from a drawable, it never fully paints the image on the screen.<br />
<br />
Typically people (read: the react-native docs) tell you to do your images something like:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><Image source={require('./my-icon.png')} /></span><br />
<br />
That mostly works, but require returns a Promise and it seems like when something goes weird in the paint lifecycle stuff can go bad. There is lots of discussion out there about using the resolve asset functions from the image library, but this causes much weirdness between the debug and release variants of your app. You can do <span style="font-family: "courier new" , "courier" , monospace;">Promise.all([])</span> from <span style="font-family: "courier new" , "courier" , monospace;">UNSAFE_componentWillMount</span>. But there is an easier way!<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">import myIcon from './my-icon.png';</span><br />
<br />
Why is this better than <span style="font-family: "courier new" , "courier" , monospace;">const myIcon = require('./my-icon.png')</span>? Well import still does the same thing under the hood that <span style="font-family: "courier new" , "courier" , monospace;">require()</span> does. The difference is import demands that all the required things are fully resolved before it begins evaluating the the script at all. This means that your image assets are guaranteed to be loaded before the script evaluates. Lemon squeezy.<br />
<br />
<br />Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-88716541086120289462018-05-31T15:37:00.000-07:002018-05-31T16:40:47.172-07:00Mobile BDD with Appium and Cucumber: Capturing Testing Data (Part 3)Of a series: <a href="http://blog.coop.software/2018/05/bdd-for-android-hello-world.html">Part 1</a>, <a href="http://blog.coop.software/2018/05/multi-platform-bdd-with-cucumber-and.html">Part 2</a>.<br />
<br />
The code for this exercise is available on the <a href="https://github.com/kebernet/appium_cucumber/tree/WITH_GIF">WITH_GIF</a> branch.<br />
<br />
One of the problems with doing automated UI testing in a CI environment is understanding failures. Today we are going to look at extending our Cucumber drivers to help with that. We are going to make a recording of what we are doing on the client side, and capture the log information from the client when there is a failure.<br />
<br />
Cucumber for Java, like JUnit or TestNG or whatever else you might for testing has a <span style="font-family: "courier new" , "courier" , monospace;">@Before</span> and <span style="font-family: "courier new" , "courier" , monospace;">@After</span> annotation that you can use to set up state for a test. The thing is, the "test" here is going to be a <i>Scenario</i> in your Cucumber tests. We are going to start here, though, with a before and after <i>Step</i> bit of code, so we need to do that ourselves. Revisiting our <span style="font-family: "courier new" , "courier" , monospace;">BaseSteps</span> class...<br />
<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">private void </span><span style="color: #ffc66d;">beforeStep</span>() {
<span style="color: #cc7832;">
</span>}
<span style="color: #cc7832;">private void </span><span style="color: #ffc66d;">afterStep</span>() {
<span style="color: #cc7832;">
</span>}
<span style="color: #cc7832;">private void </span><span style="color: #ffc66d;">doStep</span>(ThrowRunnable runnable) <span style="color: #cc7832;">throws </span>Exception {
beforeStep()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> try </span>{
runnable.run()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">finally </span>{
afterStep()
<span style="color: #cc7832;">;</span><span style="color: #cc7832;"> </span>}
}
<span style="color: #cc7832;">private interface </span>ThrowRunnable {
<span style="color: #cc7832;">void </span><span style="color: #ffc66d;">run</span>() <span style="color: #cc7832;">throws </span>Exception<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
Here we have created a method we can use to wrap a step with a generic <span style="font-family: "courier new" , "courier" , monospace;">beforeStep()</span> and <span style="font-family: "courier new" , "courier" , monospace;">afterStep()</span> method. We will need to get these invoked, but with Java 8+ closures, this is easy. We simply do a no args call in each of our step methods.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #bbb529;">@Then</span>(<span style="color: #6a8759;">"the </span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">(.*)</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;"> is gone"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">assertMissing</span>(String text) <span style="color: #cc7832;">throws </span>Exception {
doStep(()-><span style="color: #9876aa;">strategy</span>.assertMissing(<span style="color: #b389c5;">text</span>))<span style="color: #cc7832;">;
</span>}</span><span style="font-family: "droid sans mono";">
</span></pre>
<div>
<br /></div>
Now, let's start by getting a screenshot and logs before and after each step. We will create a Recorder class with some static fields we will use to capture this information.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public class </span>Recorder {
<span style="color: #cc7832;">private static final </span>Logger <span style="color: #9876aa; font-style: italic;">LOGGER </span>= Logger.<span style="font-style: italic;">getLogger</span>(
Recorder.<span style="color: #cc7832;">class</span>.getCanonicalName()
)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> private static </span>List<File> <span style="color: #9876aa; font-style: italic;">IMAGES</span><span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> private static </span>List<LogEntry> <span style="color: #9876aa; font-style: italic;">LOGS</span><span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> public static void </span><span style="color: #ffc66d;">record</span>(File file) {
<span style="color: #9876aa; font-style: italic;">IMAGES</span>.add(file)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #cc7832;">public static void </span><span style="color: #ffc66d;">log</span>(List<LogEntry> logs){
<span style="color: #9876aa; font-style: italic;">LOGS </span>= logs<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}</span></pre>
<br />
<br />
Now, let's instrument our platform strategies to give us this information. For Android:<br />
<br />
<pre style="background-color: #2b2b2b; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #bbb529;">@Override
</span><span style="color: #cc7832;">public </span><span style="color: #a9b7c6;">List<LogEntry> </span><span style="color: #ffc66d;">getLogEntries</span><span style="color: #a9b7c6;">() {
</span><span style="color: #cc7832;">return </span><span style="color: #a9b7c6;">getDriver().manage().logs().get(</span><span style="color: #6a8759;">"logcat"</span><span style="color: #a9b7c6;">).filter(Level.</span><span style="color: #9876aa; font-style: italic;">ALL</span><span style="color: #a9b7c6;">)</span><span style="color: #cc7832;">;
</span><span style="color: #a9b7c6;">}
</span><span style="color: #bbb529;">@Override
</span><span style="color: #cc7832;">public </span><span style="color: #a9b7c6;">File </span><span style="color: #ffc66d;">getScreenshotAsFile</span><span style="color: #a9b7c6;">() {
</span><span style="color: #cc7832;">return </span><span style="color: #a9b7c6;">getDriver().getScreenshotAs(OutputType.</span><span style="color: #9876aa; font-style: italic;">FILE</span><span style="color: #a9b7c6;">)</span><span style="color: #cc7832;">;
</span><span style="color: #a9b7c6;">}</span></span></pre>
<br />
... and iOS:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #bbb529;">@Override
</span><span style="color: #cc7832;">public </span>List<LogEntry> <span style="color: #ffc66d;">getLogEntries</span>() {
List<LogEntry> allEntries = <span style="color: #cc7832;">new </span>ArrayList<>()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>getDriver().manage().logs().getAvailableLogTypes()
.stream()</span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"> .filter(Objects::<span style="font-style: italic;">nonNull</span>)
.flatMap(s -> {
<span style="color: #cc7832;">try </span>{
<span style="color: #cc7832;">return </span>getDriver().manage().logs().get(s)
.filter(Level.<span style="color: #9876aa; font-style: italic;">ALL</span>).stream()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">catch </span>(Exception e) {
<span style="color: #cc7832;">return </span>Stream.<span style="font-style: italic;">empty</span>()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
})
.filter(Objects::<span style="font-style: italic;">nonNull</span>)
.forEach(allEntries::add)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>allEntries.sort((o1<span style="color: #cc7832;">, </span>o2) -> Long.<span style="font-style: italic;">compare</span>(o2.getTimestamp()<span style="color: #cc7832;">,
</span> o1.getTimestamp()))<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> return </span>allEntries<span style="color: #cc7832;">;
</span>}
<span style="color: #cc7832;">public </span>File <span style="color: #ffc66d;">getScreenshotAsFile</span>() {
<span style="color: #cc7832;">return </span>getDriver().getScreenshotAs(OutputType.<span style="color: #9876aa; font-style: italic;">FILE</span>)<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
Since iOS has a few different log files, we need to merge them all together into a single sorted list. For Android, hey, "logcat" is probably what we want anyway. Each of the drivers will give us a screenshot to a temp file.<br />
<br />
Now, let's revisit the <span style="font-family: Courier New, Courier, monospace;">beforeStep()</span> and a<span style="font-family: Courier New, Courier, monospace;">fterStep()</span> we created earlier, and capture all this information.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">private void </span><span style="color: #ffc66d;">beforeStep</span>() {
Recorder.<span style="font-style: italic;">record</span>(<span style="color: #9876aa;">strategy</span>.getScreenshotAsFile())<span style="color: #cc7832;">;
</span>}
<span style="color: #bbb529;">@SuppressWarnings</span>(<span style="color: #6a8759;">"unchecked"</span>)
<span style="color: #cc7832;">private void </span><span style="color: #ffc66d;">afterStep</span>() {
Recorder.<span style="font-style: italic;">log</span>(<span style="color: #9876aa;">strategy</span>.getLogEntries())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>Recorder.<span style="font-style: italic;">record</span>(<span style="color: #9876aa;">strategy</span>.getScreenshotAsFile())<span style="color: #cc7832;">;
</span>}</span></pre>
<div>
<br /></div>
So we get a screenshot before and after each step, and record the logs after each step.<br />
<br />
Now let's bring it all together and persist our information for failing Scenarios. We can do this by adding the <span style="font-family: "courier new" , "courier" , monospace;">@Before</span> and <span style="font-family: "courier new" , "courier" , monospace;">@After</span> hook annotations to our recorder class. This will create a new instance of the class, but we can still refer to the <span style="font-family: "courier new" , "courier" , monospace;">static</span> variables.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #bbb529;">@Before
</span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">initialize</span>() {
<span style="color: #9876aa; font-style: italic;">IMAGES </span>= <span style="color: #cc7832;">new </span>ArrayList<>()<span style="color: #cc7832;">;</span></span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><pre style="font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #9876aa; font-style: italic;"> LOGS </span>= <span style="color: #cc7832;">new </span>ArrayList<>()<span style="color: #cc7832;">;</span></span></pre>
<span style="font-family: "courier new" , "courier" , monospace;">}
<span style="color: #bbb529;">@After
</span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">finalize</span>(Scenario scenario) <span style="color: #cc7832;">throws </span>IOException {
<span style="color: #cc7832;">if </span>(scenario.isFailed()) {
File outDir = <span style="color: #cc7832;">new </span>File(<span style="color: #6a8759;">"build/cucumber-images"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>outDir.mkdirs()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>outDir.mkdir()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> if</span>(<span style="color: #9876aa; font-style: italic;">IMAGES</span>.isEmpty()){
<span style="color: #cc7832;">return;
</span><span style="color: #cc7832;"> </span>}
BufferedImage first = ImageIO.<span style="font-style: italic;">read</span>(<span style="color: #9876aa; font-style: italic;">IMAGES</span>.iterator().next())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>File destination = <span style="color: #cc7832;">new </span>File(outDir<span style="color: #cc7832;">,
</span> scenario.getName().replaceAll(<span style="color: #6a8759;">"[^</span><span style="color: #cc7832;">\\</span><span style="color: #6a8759;">w]"</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"_"</span>) +
<span style="color: #6a8759;">".gif"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> try </span>(
ImageOutputStream outputStream =
<span style="color: #cc7832;"> new </span>FileImageOutputStream(destination)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>AnimatedGIFEncoder encoder =
<span style="color: #cc7832;"> new </span>AnimatedGIFEncoder(outputStream<span style="color: #cc7832;">,
</span> first.getType()<span style="color: #cc7832;">, </span><span style="color: #6897bb;">750</span><span style="color: #cc7832;">, true</span>)) {
<span style="color: #9876aa; font-style: italic;">IMAGES</span>.stream()
.map(f -> {</span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: #cc7832;">try </span>{
<span style="color: #cc7832;">return </span>ImageIO.<span style="font-style: italic;">read</span>(f)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">catch </span>(Exception e) {
<span style="color: #cc7832;">throw new </span>RuntimeException(e)<span style="color: #cc7832;">;</span></span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;"> </span>}
})
.forEach(i -> {
<span style="color: #cc7832;">try </span>{
<span style="color: #b389c5;">encoder</span>.writeToSequence(i)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">catch </span>(IOException e) {
<span style="color: #cc7832;">throw new </span>RuntimeException(e)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
})<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #9876aa; font-style: italic;">LOGGER</span>.info(<span style="color: #6a8759;">"Wrote scenario animation to " </span>+
destination.getAbsolutePath())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>ByteArrayOutputStream baos = <span style="color: #cc7832;">new </span>ByteArrayOutputStream()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>ByteStreams.<span style="font-style: italic;">copy</span>(<span style="color: #cc7832;">new </span>FileInputStream(destination)<span style="color: #cc7832;">, </span>baos)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>scenario.embed(baos.toByteArray()<span style="color: #cc7832;">, </span><span style="color: #6a8759;">"image/gif"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>scenario.embed(logFile()<span style="color: #cc7832;">, </span><span style="color: #6a8759;">"text/plain"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}
<span style="color: #cc7832;">private byte</span>[] <span style="color: #ffc66d;">logFile</span>(){
StringBuilder sb = <span style="color: #cc7832;">new </span>StringBuilder()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span><span style="color: #9876aa; font-style: italic;">LOGS</span>.stream()
.map(e-> <span style="color: #cc7832;">new </span>Date(e.getTimestamp()) + <span style="color: #6a8759;">"," </span>+
e.getLevel().getName() + <span style="color: #6a8759;">", " </span>+ e.getMessage()
)
.forEach(line-> <span style="color: #b389c5;">sb</span>.append(line).append(<span style="color: #6a8759;">"</span><span style="color: #cc7832;">\n</span><span style="color: #6a8759;">"</span>))<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> return </span>sb.toString().getBytes(Charsets.<span style="color: #9876aa; font-style: italic;">UTF_8</span>)<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
So in our <span style="font-family: "courier new" , "courier" , monospace;">@Before</span> we initialize the static members. Then in the <span style="font-family: "courier new" , "courier" , monospace;">@After</span> we finalize everything. If there are no images we can bounce. If there are, we will create an <span style="font-family: "courier new" , "courier" , monospace;">AnimatedGIFEncoder</span> class and add all the images to it. I'm not going to get into the image processing thing, but you should pay attention to the last two methods of the <span style="font-family: "courier new" , "courier" , monospace;">finalize()</span> method: by getting the Cucumber <span style="font-family: "courier new" , "courier" , monospace;">Scenario</span> object passed into the method at the end, we can embed other data in the results by MIME type.<br />
<br />
Now if we want to see the data we collect, we can add a reporting plugin to our build.gradle file:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">buildscript {
repositories {
maven {
url <span style="color: #6a8759;">"http://repo.bodar.com"
</span><span style="color: #6a8759;"> </span>}
maven {
url <span style="color: #6a8759;">"https://plugins.gradle.org/m2/"
</span><span style="color: #6a8759;"> </span>}
}
dependencies {
classpath <span style="color: #6a8759;">"com.github.samueltbrown:gradle-cucumber-plugin:0.9"
</span><span style="color: #6a8759;"> </span>classpath <span style="color: #6a8759;">"gradle.plugin.com.github.spacialcircumstances:" +</span></span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #6a8759;"> "gradle-cucumber-reporting:0.0.11"
</span><span style="color: #6a8759;"> </span>}
}
plugins {
id <span style="color: #6a8759;">'java'
</span><span style="color: #6a8759;"> </span>id <span style="color: #6a8759;">"com.github.samueltbrown.cucumber" </span>version <span style="color: #6a8759;">"0.9"
</span><span style="color: #6a8759;"> </span>id <span style="color: #6a8759;">'idea'
</span><span style="color: #6a8759;"> </span>id <span style="color: #6a8759;">"com.github.spacialcircumstances.gradle-cucumber-reporting" </span>version <span style="color: #6a8759;">"0.0.11"
</span>}
</span><pre style="font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">cucumberReports {
<span style="color: #9876aa;">outputDir </span>= file(<span style="color: #6a8759;">"</span>$<span style="color: #9876aa;">project</span>.<span style="color: #9876aa;">buildDir</span><span style="color: #6a8759;">/reports"</span>)
<span style="color: #9876aa;">buildName </span>= <span style="color: #6a8759;">'0'
</span><span style="color: #6a8759;"> </span><span style="color: #9876aa;">reports </span>= files(<span style="color: #6a8759;">"</span>$<span style="color: #9876aa;">project</span>.<span style="color: #9876aa;">buildDir</span><span style="color: #6a8759;">/cucumber.json"</span>)
}
// stuff here</span></pre>
<pre style="font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">
</span></pre>
<pre style="font-size: 9pt;"><pre style="font-size: 9pt;"><span style="font-family: "droid sans mono";">
</span><span style="font-family: "courier new" , "courier" , monospace;">tasks.<span style="color: #9876aa;">cucumber</span>.finalizedBy generateCucumberReports</span></pre>
</pre>
</pre>
<div>
<br /></div>
Now when our cucumber gradle <span style="font-family: "courier new" , "courier" , monospace;">cucumber</span> task runs, we will get a report telling us what failed, like so:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-kv-iPYCo6mGX1tbp_kjDSwKl4BElBnn8zOCMm6PUO6Lw0TBLMZrS3j4OmVwKpOGHKa3tu2xh4Bs11d6nv1YPxDvQxLfmrrmxTYHKXbgZldLGq0uaXzJCmwu9gfJq0fa-IPg_dyq3RI/s1600/cucumber+report.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1031" data-original-width="1600" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-kv-iPYCo6mGX1tbp_kjDSwKl4BElBnn8zOCMm6PUO6Lw0TBLMZrS3j4OmVwKpOGHKa3tu2xh4Bs11d6nv1YPxDvQxLfmrrmxTYHKXbgZldLGq0uaXzJCmwu9gfJq0fa-IPg_dyq3RI/s400/cucumber+report.png" width="400" /></a></div>
<br />
<br />
(this image not animated)<br />
<br /></div>
Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-21789561359882330852018-05-07T09:25:00.001-07:002018-05-07T10:39:41.599-07:00Multi-Platform BDD with Cucumber and Appium (Part 2)<a href="http://blog.coop.software/2018/05/bdd-for-android-hello-world.html">Previously, on Battlestar Galactica...</a><br />
<br />
In the last post, we set up a simple BDD test for an Android app. We defined some general BaseSteps that allowed us to look for text on the screen and click it. In this exercise we are going to abstract this out so that we can perform the same test on multiple platforms using Guice injection.<br />
<br />
Source code for this version with the changes from Part 1 is available on the <a href="https://github.com/kebernet/appium_cucumber/tree/WITH_GUICE"><span style="font-family: "courier new" , "courier" , monospace;">WITH_GUICE</span> branch on GitHub</a>.<br />
<br />
As you saw in the last article, the biding between step definitions and feature files is handled via Java annotations. By adding the <span style="font-family: "courier new" , "courier" , monospace;">cucumber-guice</span> library we can provide a platform strategy that will let us define these common step definitions across platforms based on execution time parameters.<br />
<br />
If you are like me, you are going to be wondering about the decisions that have been make here from an architecture standpoint. So let's cover some of the weirdness here...<br />
<br />
<ol>
<li><span style="font-family: "courier new" , "courier" , monospace;">cucumber-guice</span> doesn't seem to know how to introspect abstract classes for step definitions. You need a concrete class for that.</li>
<li>If you have two concrete classes with matching <span style="font-family: "courier new" , "courier" , monospace;">@Override</span> methods, it is going to yell at you about duplicate step definitions.</li>
<li>I have elected to overcome these difficulties by using a "Strategy" pattern. We have preserved our BaseSteps class from the previous example, but now it simply delegates calls to a strategy implementation <span style="font-family: "courier new" , "courier" , monospace;">@Inject</span>-ed when it is created.</li>
<li>We're going to spend more time looking at design patterns for BDD tests in the next post, but for now we just want to add muti-platform support to our testing scenario.</li>
</ol>
<div>
All that said, let's get started...</div>
<div>
<br /></div>
<div>
The first thing we want to do us update our dependencies in the integration module from the previous example we are adding two lines here:</div>
<div>
<br /></div>
<div>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">dependencies {
cucumberRuntime <span style="color: #6a8759;">'info.cukes:cucumber-java:1.2.5'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'info.cukes:cucumber-java:1.2.5'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'info.cukes:cucumber-guice:1.2.5'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'com.google.inject:guice:4.2.0'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'junit:junit:4.12'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'io.appium:java-client:3.3.0'
</span>}</span></pre>
</div>
<div>
<br /></div>
<div>
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">cucumber-guice</span> dependency is new. Because, for some FSM damned reason, the <span style="font-family: "courier new" , "courier" , monospace;">cucumber-guice</span> module doesn't have a declared dependency on Guice, we also add a dependency on Guice. I really got nothing here. You have to do it or it just won't work.</div>
<div>
<br /></div>
<div>
Now we have the option to inject dependencies into our step definitions. If all you want is some simple state definitions, you can do that with the regular <span style="font-family: "courier new" , "courier" , monospace;">javax.inject</span> annotation, or the Cucumber annotations, but we will get to that. Right now, though, we want to change our execution based on platform, so we need to modify our <span style="font-family: "courier new" , "courier" , monospace;">build.gradle</span> to pass a new parameter to the test execution.</div>
<div>
<br /></div>
<div>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">cucumber {
<span style="color: #9876aa;">formats </span>= [<span style="color: #6a8759;">'pretty'</span>, <span style="color: #6a8759;">'json:build/cucumber.json'</span>, <span style="color: #6a8759;">'junit:build/cucumber.xml'</span>]
jvmOptions {
maxHeapSize = <span style="color: #6a8759;">'512m'
</span><span style="color: #6a8759;"> </span>environment <span style="color: #6a8759;">'apk'</span>, <span style="color: #9876aa;">rootProject</span>.project(<span style="color: #6a8759;">":app"</span>).<span style="color: #9876aa;">buildDir</span>.getAbsolutePath() +
<span style="color: #6a8759;">"/outputs/apk/debug/app-debug.apk"
</span><span style="color: #6a8759;"> </span>environment <span style="color: #6a8759;">'platform'</span>, System.<span style="color: #9876aa; font-style: italic;">getProperty</span>(<span style="color: #6a8759;">"platform"</span>) == <span style="color: #cc7832;">null </span>?
<span style="color: #6a8759;">"android" </span>:
System.<span style="color: #9876aa; font-style: italic;">getProperty</span>(<span style="color: #6a8759;">"platform"</span>);
}
}</span></pre>
</div>
<div>
<br />
So we are just going to read a system property here and default to android if it is undefined, then pass that value to the execution environment for Cucumber.</div>
<div>
<br /></div>
<div>
Now, we have a bit of boilerplate to create. Again going to interesting design decisions, c<span style="font-family: "courier new" , "courier" , monospace;">ucumber-guice</span> doesn't allow you to simply declare modules to include. However, you can provide a factory class for the Guice injector it will use. Just so you understand the subtleties of this, lets be clear about what is happening here: Cucumber scans the <span style="font-family: "courier new" , "courier" , monospace;">classpath</span> for method implementations with a step definition (<span style="font-family: "courier new" , "courier" , monospace;">@Given</span>, <span style="font-family: "courier new" , "courier" , monospace;">@Whe</span>n, <span style="font-family: "courier new" , "courier" , monospace;">@Then</span>), and then with<span style="font-family: "courier new" , "courier" , monospace;"> cucumber-guice</span>, asks the <span style="font-family: "courier new" , "courier" , monospace;">Injector</span> for an implementation of that class. This is why you can't have multiple simple implementations of a step definition floating around, and why we have opted for a strategy pattern to provide multi-platform implementations. Again, we will look at this in more detail in the next post. All this hand-waving aside, we need to create an <span style="font-family: "courier new" , "courier" , monospace;">InjectorSource</span> implementation:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public class </span>ConfiguredInjectorSource <span style="color: #cc7832;">implements </span>InjectorSource {
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public </span>Injector <span style="color: #ffc66d;">getInjector</span>() {
<span style="color: #cc7832;">return </span>Guice.<span style="font-style: italic;">createInjector</span>(CucumberModules.<span style="color: #9876aa; font-style: italic;">SCENARIO</span><span style="color: #cc7832;">,
new </span>CucumberModule())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}</span></pre>
</div>
<div>
<br /></div>
<div>
When we create our Guice injector, we need to include the <span style="font-family: "courier new" , "courier" , monospace;">SCENARIO</span> module. This defines a <span style="font-family: "courier new" , "courier" , monospace;">@ScenarioScoped</span> annotation that we can use later when creating our injected classes. We aren't going to use it for this exercise, but it is required to bootstrap <span style="font-family: "courier new" , "courier" , monospace;">cucumber-guice</span>. Here we have added this default module and our module.<br />
<br />
Finally, we need to declare the CucumberModule class. We are going to read the environment variable we defined in our Gradle file and do an implementation swap.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public class </span>CucumberModule <span style="color: #cc7832;">extends </span>AbstractModule {
<span style="color: #cc7832;">private static final </span>Logger <span style="color: #9876aa; font-style: italic;">LOGGER </span>= Logger.<span style="font-style: italic;">getLogger</span>(
CucumberModule.<span style="color: #cc7832;">class</span>.getCanonicalName()
)<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">protected void </span><span style="color: #ffc66d;">configure</span>() {
String platform = System.<span style="font-style: italic;">getenv</span>(<span style="color: #6a8759;">"platform"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span><span style="color: #9876aa; font-style: italic;">LOGGER</span>.info(<span style="color: #6a8759;">"Configuring run for platform: "</span>+platform)<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> switch</span>(platform){
<span style="color: #cc7832;">case </span><span style="color: #6a8759;">"android"</span>:
bind(BaseStepsStrategy.<span style="color: #cc7832;">class</span>)
.to(AndroidBaseSteps.<span style="color: #cc7832;">class</span>)
.in(<span style="color: #bbb529;">Singleton</span>.<span style="color: #cc7832;">class</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> break;
</span><span style="color: #cc7832;"> case </span><span style="color: #6a8759;">"ios"</span>:
bind(BaseStepsStrategy.<span style="color: #cc7832;">class</span>)
.to(IOSBaseSteps.<span style="color: #cc7832;">class</span>)
.in(<span style="color: #bbb529;">Singleton</span>.<span style="color: #cc7832;">class</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> break;
</span><span style="color: #cc7832;"> default</span>:
<span style="color: #cc7832;">throw new </span>RuntimeException(
<span style="color: #6a8759;"> "Unknown platform environment variable: " </span>+
platform)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}
}</span></pre>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
This feels like a crazy number of lines for what we are doing here, but you know, cope. We read the environment variable, we log it so the user knows what is going on, then we do a switch around the <span style="font-family: "courier new" , "courier" , monospace;">BaseStepsStrategy</span> to provide an implementation.<br />
<br />
This is all well and good, but our test execution is still going to depend on <span style="font-family: "courier new" , "courier" , monospace;">BaseSteps</span> from the previous exercise. So what we are going to do is rework this class to delegate to our strategy implementations, declare itself as a <span style="font-family: "courier new" , "courier" , monospace;">@Singleton</span>, and get the strategy implementation injected into it.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #bbb529;">@Singleton
</span><span style="color: #cc7832;">public class </span>BaseSteps {
<span style="color: #cc7832;">private final </span>BaseStepsStrategy <span style="color: #9876aa;">strategy</span><span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #bbb529;">@Inject
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public </span><span style="color: #ffc66d;">BaseSteps</span>(BaseStepsStrategy baseSteps){
<span style="color: #cc7832;">this</span>.<span style="color: #9876aa;">strategy </span>= baseSteps<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Given</span>(<span style="color: #6a8759;">"I have launched the application"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">startApp</span>() <span style="color: #cc7832;">throws </span>IOException{
<span style="color: #9876aa;">strategy</span>.startApp()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@When</span>(<span style="color: #6a8759;">"I click the </span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">(.*)</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;"> button"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">clickByText</span>(String text){
<span style="color: #9876aa;">strategy</span>.clickByText(text)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Then</span>(<span style="color: #6a8759;">"the </span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">(.*)</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;"> is gone"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">assertMissing</span>(String text){
<span style="color: #9876aa;">strategy</span>.assertMissing(text)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}</span></pre>
</div>
<div>
<br /></div>
<div>
What about all the code we had from the previous exercise? Well, we're gonna copy and paste that into our AndroidBaseSteps class, but first, we're gonna create a generic abstract strategy here.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public abstract class </span>BaseStepsStrategy<<span style="color: #507874;">T </span><span style="color: #cc7832;">extends </span>WebDriver> {
<span style="color: #cc7832;">private </span><span style="color: #507874;">T </span><span style="color: #9876aa;">driver</span><span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #ffc66d;">BaseStepsStrategy</span>() <span style="color: #cc7832;">throws </span>MalformedURLException {
<span style="color: #cc7832;">this</span>.<span style="color: #9876aa;">driver </span>= createDriver()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #cc7832;">protected abstract </span><span style="color: #507874;">T </span><span style="color: #ffc66d;">createDriver</span>() <span style="color: #cc7832;">throws </span>MalformedURLException<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #507874;">T </span><span style="color: #ffc66d;">getDriver</span>(){
<span style="color: #cc7832;">return this</span>.<span style="color: #9876aa;">driver</span><span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #cc7832;">public abstract void </span><span style="color: #ffc66d;">startApp</span>() <span style="color: #cc7832;">throws </span>IOException<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> public abstract void </span><span style="color: #ffc66d;">clickByText</span>(String text)<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> public abstract void </span><span style="color: #ffc66d;">assertMissing</span>(String text)<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
I know that <span style="font-family: "courier new" , "courier" , monospace;">WebDriver</span> seems like a weird thing to extend from here, but <span style="font-family: "courier new" , "courier" , monospace;">MobileDriver</span> for Appium actually extends from <span style="font-family: "courier new" , "courier" , monospace;">WebDriver</span> -- I guess no one has gone back and just made "<span style="font-family: "courier new" , "courier" , monospace;">AppDriver</span>" as a thing from the Selenium group. Because we want the "driver" to continue to be a singleton in the runtime, we have kicked it out to a <span style="font-family: "courier new" , "courier" , monospace;">createDriver()</span> method. The reason is obvious when we create our <span style="font-family: "courier new" , "courier" , monospace;">AndroidBaseSteps</span> class.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public class </span>AndroidBaseSteps <span style="color: #cc7832;">extends </span>BaseStepsStrategy<AndroidDriver> {
<span style="color: #cc7832;">public </span><span style="color: #ffc66d;">AndroidBaseSteps</span>() <span style="color: #cc7832;">throws </span>MalformedURLException {
<span style="color: #cc7832;">super</span>()<span style="color: #cc7832;">;</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">protected </span>AndroidDriver <span style="color: #ffc66d;">createDriver</span>() <span style="color: #cc7832;">throws </span>MalformedURLException {
File app = <span style="color: #cc7832;">new </span>File(System.<span style="font-style: italic;">getenv</span>(<span style="color: #6a8759;">"apk"</span>))<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>DesiredCapabilities capabilities = <span style="color: #cc7832;">new </span>DesiredCapabilities()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"deviceName"</span><span style="color: #cc7832;">,</span><span style="color: #6a8759;">"Android Emulator"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"app"</span><span style="color: #cc7832;">, </span>app.getAbsolutePath())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"appPackage"</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"net.kebernet.appium_cucumber"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"appActivity"</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">".MainActivity"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> return new </span>AndroidDriver<>(<span style="color: #cc7832;">new </span>URL(<span style="color: #6a8759;">"http://127.0.0.1:4723/wd/hub"</span>)<span style="color: #cc7832;">,
</span> capabilities)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">startApp</span>() <span style="color: #cc7832;">throws </span>IOException {
getDriver().resetApp()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">clickByText</span>(String text) {
getDriver().findElementByAndroidUIAutomator(
<span style="color: #6a8759;"> "new UiSelector().textContains(</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">"</span>+text+<span style="color: #6a8759;">"</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">)"</span>)
.click()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">assertMissing</span>(String text) {
MobileElement element = <span style="color: #cc7832;">null;
</span><span style="color: #cc7832;"> try </span>{
element = (MobileElement) getDriver()
.findElementByAndroidUIAutomator(
<span style="color: #6a8759;"> "new UiSelector().textContains(</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">" </span>+ text + <span style="color: #6a8759;">"</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">)"</span>)<span style="color: #cc7832;">;</span>
} <span style="color: #cc7832;">catch</span>(NoSuchElementException e){
<span style="color: grey;">//expected exception;
</span><span style="color: grey;"> </span>}
<span style="font-style: italic;">assertTrue</span>(element == <span style="color: #cc7832;">null</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
}</span></pre>
<br />
<br />
Aside from a bit of boilerplate, this looks pretty much exactly like out <span style="font-family: "courier new" , "courier" , monospace;">BaseSteps</span> class from the first example. We are creating the driver, by delegation, in the constructor, but since this is a generic implementation, we can use <span style="font-family: "courier new" , "courier" , monospace;">getDriver()</span> everywhere and know we are starting with an <span style="font-family: "courier new" , "courier" , monospace;">AndroidDriver</span>. We do have a new cast in the <span style="font-family: "courier new" , "courier" , monospace;">assertMissing()</span> method, but that is a small price to pay.</div>
<div>
<br /></div>
<div>
We are now back to a "known good" state for our application and tests. Now, let's look at making our "integration" suite work with iOS.<br />
<br />
We will start with our iOS app, that is basically the same as our Android app...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqf9RaOaBMBqStuTa4VsCzhHVj5X9_icmEJSQuzoKOfokX9quvq6dtDD90UZj-xtdA4VceFRUceM57WTmXSifI8n3SOyFXJCLUFOKDe9OqJr6ba4fz2qqNxGG0WKS3AFUMO5aG_vImK_A/s1600/screen-ios.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1378" data-original-width="750" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqf9RaOaBMBqStuTa4VsCzhHVj5X9_icmEJSQuzoKOfokX9quvq6dtDD90UZj-xtdA4VceFRUceM57WTmXSifI8n3SOyFXJCLUFOKDe9OqJr6ba4fz2qqNxGG0WKS3AFUMO5aG_vImK_A/s400/screen-ios.png" width="217" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Next we need to implement our <span style="font-family: "courier new" , "courier" , monospace;">IOSBaseSteps</span> class. This is going to look largely like our Android version we already have, only this time we are going to use the XPath selector. We are also adding a new configuration to the environment configuration in the build.gradle to pass a path to our .app build.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #cc7832;">public class </span>IOSBaseSteps <span style="color: #cc7832;">extends </span>BaseStepsStrategy<IOSDriver<MobileElement>> {
<span style="color: #cc7832;">public </span><span style="color: #ffc66d;">IOSBaseSteps</span>() <span style="color: #cc7832;">throws </span>MalformedURLException {
<span style="color: #cc7832;">super</span>()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">protected </span>IOSDriver<MobileElement> <span style="color: #ffc66d;">createDriver</span>() <span style="color: #cc7832;">throws </span>MalformedURLException {
File app = <span style="color: #cc7832;">new </span>File(System.<span style="font-style: italic;">getenv</span>(<span style="color: #6a8759;">"app"</span>))<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span>DesiredCapabilities capabilities = <span style="color: #cc7832;">new </span>DesiredCapabilities()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(MobileCapabilityType.<span style="color: #9876aa; font-style: italic;">PLATFORM_NAME</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"iOS"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(MobileCapabilityType.<span style="color: #9876aa; font-style: italic;">PLATFORM_VERSION</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"11.3"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(MobileCapabilityType.<span style="color: #9876aa; font-style: italic;">DEVICE_NAME</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"iPhone Simulator"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(MobileCapabilityType.<span style="color: #9876aa; font-style: italic;">APP</span><span style="color: #cc7832;">, </span>app.getAbsolutePath())<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> return new </span>IOSDriver<>(<span style="color: #cc7832;">new </span>URL(<span style="color: #6a8759;">"http://127.0.0.1:4723/wd/hub"</span>)<span style="color: #cc7832;">, </span>capabilities)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">startApp</span>() <span style="color: #cc7832;">throws </span>IOException {
getDriver().resetApp()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">clickByText</span>(String text) {
MobileElement element = getDriver().findElementByXPath(
<span style="color: #6a8759;"> "//*[contains(@label, '"
</span>+ text + <span style="color: #6a8759;">"')]"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>element.click()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>}
<span style="color: #bbb529;">@Override
</span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">assertMissing</span>(String text) {
MobileElement element = <span style="color: #cc7832;">null;
</span><span style="color: #cc7832;"> try </span>{
element = getDriver().findElementByXPath(
<span style="color: #6a8759;"> "//*[contains(@label, '"
</span>+ text + <span style="color: #6a8759;">"')]"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">catch</span>(NoSuchElementException e){
<span style="color: grey;">//expected execption;
</span><span style="color: grey;"> </span>}
<span style="font-style: italic;">assertNull</span>(element)<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span>}</span></pre>
<br />
And our change to the build.gradle file:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: "courier new" , "courier" , monospace;">cucumber {
<span style="color: #9876aa;">formats </span>= [<span style="color: #6a8759;">'pretty'</span>, <span style="color: #6a8759;">'json:build/cucumber.json'</span>, <span style="color: #6a8759;">'junit:build/cucumber.xml'</span>]
jvmOptions {
maxHeapSize = <span style="color: #6a8759;">'512m'</span><span style="color: #6a8759;">
</span><span style="color: #6a8759;"> </span>environment <span style="color: #6a8759;">'apk'</span>, <span style="color: #9876aa;">rootProject</span>.project(<span style="color: #6a8759;">":app"</span>).<span style="color: #9876aa;">buildDir</span>.getAbsolutePath() +
<span style="color: #6a8759;">"/outputs/apk/debug/app-debug.apk"</span><span style="color: #6a8759;">
</span><span style="color: #6a8759;"> </span>environment <span style="color: #6a8759;">'platform'</span>, System.<span style="color: #9876aa; font-style: italic;">getProperty</span>(<span style="color: #6a8759;">"platform"</span>) == <span style="color: #cc7832;">null </span>?
<span style="color: #6a8759;">"android" </span>:
System.<span style="color: #9876aa; font-style: italic;">getProperty</span>(<span style="color: #6a8759;">"platform"</span>)
environment <span style="color: #6a8759;">'app'</span>, <span style="color: #9876aa;">rootProject</span>.<span style="color: #9876aa;">projectDir</span>.getAbsolutePath() +
<span style="color: #6a8759;">"/ios/DerivedData/appium-cucumber/Build/Products/" </span>+
<span style="color: #6a8759;">"Debug-iphonesimulator/appium-cucumber.app"
</span><span style="color: #6a8759;"> </span>}
}</span></pre>
<div>
<br />
Now we can run our sample tests on the iOS app:</div>
<br />
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$../gradlew -Dplatform=ios cucumber</span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<br />
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">> Task :integration:cucumber </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Gradle now uses separate output directories for each JVM language, but this build assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">May 07, 2018 12:10:39 PM cucumber.inject.CucumberModule configure</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">INFO: Configuring run for platform: ios</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Feature: Click the button</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Clicking buttons is clever</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Scenario: I see a button and click it. # features/hello.feature:4</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Given I have launched the application # BaseSteps.startApp()</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> When I click the "Click Me" button # BaseSteps.clickByText(String)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Then the "Click Me" is gone # BaseSteps.assertMissing(String)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">1 Scenarios (1 passed)r</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">3 Steps (3 passed)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">2m37.075s</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">BUILD SUCCESSFUL in 2m 57s</span></div>
</div>
<div>
<br /></div>
Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-48038241776957980972018-05-04T10:19:00.000-07:002018-05-04T22:40:54.688-07:00BDD For Android Hello World<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Today I am going to demonstrate a very basic bootstrap of BDD for Android using <a href="https://cucumber.io/">Cucumber</a> and <a href="http://appium.io/">Appium</a>.<br />
<br />
You can find all of the <a href="https://github.com/kebernet/appium_cucumber">code on GitHub</a>, natch.<br />
<br />
The first step is to get Appium installed and working. I found<a href="https://github.com/isonic1/appium-workshop"> this to be the best startup instructions</a>, but it is a little old, so YMMV.<br />
<br />
First, the app. We have a very simple Android app here with a button. You click it, and it goes away.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqppZlkXh-WKWN7vf7XZRXseGm8GJFBFA8skqzoCD0nAAnk7cTuP7ustrecXfDV-OPvRE7HMAYJFCf-AEF-YQV7i-ekX8kpdfRnpFgXZ6SYqTrJKQxilSVY48of8c5HhrefebYbPMusNs/s1600/screen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1268" data-original-width="688" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqppZlkXh-WKWN7vf7XZRXseGm8GJFBFA8skqzoCD0nAAnk7cTuP7ustrecXfDV-OPvRE7HMAYJFCf-AEF-YQV7i-ekX8kpdfRnpFgXZ6SYqTrJKQxilSVY48of8c5HhrefebYbPMusNs/s320/screen1.png" width="173" /></a></div>
<br />
Now, we want to test our app. We need to set up a new Gradle module parallel to our application project, as the plugin environment we need to make this work isn't going to play well with the Android plugin. Here I have called the project "integration" to indicate this for performing integration testing.<br />
<br />
Lets break down the <span style="font-family: "courier new" , "courier" , monospace;">build.gradle</span> real fast:<br />
<br />
Apply our plugins:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;">buildscript {
repositories {
maven {
url <span style="color: #6a8759;">"http://repo.bodar.com"
</span><span style="color: #6a8759;"> </span>}
maven {
url <span style="color: #6a8759;">"https://plugins.gradle.org/m2/"
</span><span style="color: #6a8759;"> </span>}
}
dependencies {
classpath <span style="color: #6a8759;">"com.github.samueltbrown:gradle-cucumber-plugin:0.9"
</span><span style="color: #6a8759;"> </span>}
}</span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;">plugins {
id <span style="color: #6a8759;">'java'
</span><span style="color: #6a8759;"> </span>id <span style="color: #6a8759;">"com.github.samueltbrown.cucumber" </span>version <span style="color: #6a8759;">"0.9"
</span><span style="color: #6a8759;"> </span>id <span style="color: #6a8759;">'idea'
</span>}</span></pre>
<br />
Next we need to make sure our app gets built for the Cucumber plugin to run.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;"><span style="color: #9876aa;">tasks</span>.<span style="color: #9876aa;">cucumber</span>.dependsOn(<span style="color: #6a8759;">":app:assembleDebug"</span>)</span></pre>
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-family: 'Menlo'; font-size: 9.0pt;"></pre>
<br />
And point the cucumber plugin to the debug build of the application, so we can find it. Here we are going to pass an environment variable pointing to the APK file we want to test.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;">cucumber {
<span style="color: #9876aa;">formats </span>= [<span style="color: #6a8759;">'pretty'</span>, <span style="color: #6a8759;">'json:build/cucumber.json'</span>, <span style="color: #6a8759;">'junit:build/cucumber.xml'</span>]
jvmOptions {
maxHeapSize = <span style="color: #6a8759;">'512m'
</span><span style="color: #6a8759;"> </span>environment <span style="color: #6a8759;">'apk'</span>, <span style="color: #9876aa;">rootProject</span>.project(<span style="color: #6a8759;">":app"</span>).<span style="color: #9876aa;">buildDir</span>.getAbsolutePath() +
<span style="color: #6a8759;">"/outputs/apk/debug/app-debug.apk"</span><span style="color: #6a8759;">
</span> }
}
repositories {
jcenter()
maven {
url <span style="color: #6a8759;">'https://repository-saucelabs.forge.cloudbees.com/release'
</span><span style="color: #6a8759;"> </span>}
}</span><span style="font-family: menlo;">
</span></pre>
<div>
<br /></div>
Next we set up the dependencies we need for the Cucumber environment. These come in as two new Gradle configuration scopes. Finally, we are just going to use a little config magic to make sure IntelliJ IDEA can properly resolve the dependencies while we are editing these things.<br />
<div>
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;">dependencies {
cucumberRuntime <span style="color: #6a8759;">'info.cukes:cucumber-java:1.2.5'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'info.cukes:cucumber-java:1.2.5'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'junit:junit:4.12'
</span><span style="color: #6a8759;"> </span>cucumberCompile <span style="color: #6a8759;">'io.appium:java-client:3.3.0'
</span>}
idea {
module {
testSourceDirs += file(<span style="color: #6a8759;">'src/cucumber/java'</span>)
<span style="color: #9876aa;">scopes</span>.<span style="color: #6a8759;">TEST</span>.<span style="color: #6a8759;">plus</span>.add(<span style="color: #9876aa;">configurations</span>.<span style="color: #9876aa;">cucumberCompile</span>)
}
}
<span style="color: #9876aa;">sourceCompatibility </span>= <span style="color: #6a8759;">"1.8"
</span><span style="color: #9876aa;">targetCompatibility </span>= <span style="color: #6a8759;">"1.8"</span></span><span style="color: #6a8759; font-family: menlo;">
</span></pre>
<br />
Cucumber allows us to write test directives using a natural language format. The idea here is that the natural language syntax is easier to maintain as your requirements change. Our sample <span style="font-family: "courier new" , "courier" , monospace;">.feature</span> file in <span style="font-family: "courier new" , "courier" , monospace;">src/cucumber/resources</span> looks like so:<br />
<br />
<code></code><br />
<pre><code><pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;"><span style="color: #cc7832; font-weight: bold;">Feature: </span>Click the button
Clicking buttons is clever
<span style="color: #cc7832; font-weight: bold;">Scenario: </span>I see a button and click it.
Given I have launched the application
When I click the "Click Me" button
Then the "Click Me" is gone</span></pre>
</code></pre>
<code>
</code>
<br />
The first line is the name of the feature we are testing with this file. The second line is just a descriptor. It is then followed by 1..n "Scenarios" that are basically sequences of test steps. Here, the scenario is named "I see a button and click it."<br />
<br />
Next we have a number of steps. These are in the format of "Given/When/Then". Given steps are basically there to establish the baseline for the test. Here, we are just launching the app, but you could have a "Give" that navigates to a page, or logs in, or whatever. When steps are basically your interaction operations. Then steps are your assertion operations.<br />
<br />
These steps, however, are going to require some code to work. So lets get into that. Cucumber is going to look for your steps to be defined in some Java classes with methods annotated with the step definition. You can use regular expressions to pull data from the step line, as well as some other {} -type templating.<br />
<br />
So let's look at the first one: "Given I have launched the application." This is a simple method call which we annotate with the <span style="font-family: "courier new" , "courier" , monospace;">@Given</span> annotation...<br />
<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;"><span style="color: #cc7832;">public class </span>BaseSteps {
<span style="color: #cc7832;">protected </span>AndroidDriver<MobileElement> <span style="color: #9876aa;">driver</span><span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #bbb529;">@Given</span>(<span style="color: #6a8759;">"I have launched the application"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">startApp</span>() <span style="color: #cc7832;">throws </span>IOException {
File app = <span style="color: #cc7832;">new </span>File(System.<span style="font-style: italic;">getenv</span>(<span style="color: #6a8759;">"apk"</span>))<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>DesiredCapabilities capabilities = <span style="color: #cc7832;">new </span>DesiredCapabilities()<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"deviceName"</span><span style="color: #cc7832;">,</span><span style="color: #6a8759;">"Android Emulator"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"app"</span><span style="color: #cc7832;">, </span>app.getAbsolutePath())<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"appPackage"</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">"net.kebernet.appium_cucumber"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>capabilities.setCapability(<span style="color: #6a8759;">"appActivity"</span><span style="color: #cc7832;">, </span><span style="color: #6a8759;">".MainActivity"</span>)<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span><span style="color: #9876aa;">driver </span>= <span style="color: #cc7832;">new </span>AndroidDriver<>(<span style="color: #cc7832;">new </span>URL(<span style="color: #6a8759;">"http://127.0.0.1:4723/wd/hub"</span>)<span style="color: #cc7832;">,
</span> capabilities)<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span><span style="color: #9876aa;">driver</span>.resetApp()<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;"> </span>}</span></pre>
<br />
Here we start by reading the apk environment variable we configured in the Gradle file, configure the <span style="font-family: "courier new" , "courier" , monospace;">DesiredCapabilities</span> object, and create an <span style="font-family: "courier new" , "courier" , monospace;">AndroidDriver</span>. For prophylactic reasons, we do a <span style="font-family: "courier new" , "courier" , monospace;">resetApp()</span> call to just kill and restart the app so we know we have a good state. This will connect to the Appium node.js server, which in turn will install the apk file on the running emulator and spin it up.<br />
<br />
Next we want to click our button, so let's look at that one.<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;"><span style="color: #bbb529;">@When</span>(<span style="color: #6a8759;">"I click the </span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">(.*)</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;"> button"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">clickByText</span>(String text){
<span style="color: #9876aa;">driver</span>.findElementByAndroidUIAutomator(
<span style="color: #6a8759;"> "new UiSelector().textContains(</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">" </span>+
text + <span style="color: #6a8759;">"</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">)"
</span> ).click()<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
Here we are selecting the text inside the quotation marks using a regex selector. Then we take the text and go to the driver and use <span style="font-family: "courier new" , "courier" , monospace;">findElementByAndroidUIAutomator()</span> to select it. Here we are constructing a small Java snippet in a <span style="font-family: "courier new" , "courier" , monospace;">String</span> to perform the UI selection on the device, then we call <span style="font-family: "courier new" , "courier" , monospace;">click()</span> to perform the action.<br />
<br />
Finally, we want to validate the behavior: that the button goes away. To do that we look for the button again, but expect it to be gone...<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-size: 9pt;"><span style="font-family: Courier New, Courier, monospace;"><span style="color: #bbb529;">@Then</span>(<span style="color: #6a8759;">"the </span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">(.*)</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;"> is gone"</span>)
<span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">assertMissing</span>(String text){
MobileElement element = <span style="color: #cc7832;">null;
</span><span style="color: #cc7832;"> try </span>{
element = <span style="color: #9876aa;">driver</span>.findElementByAndroidUIAutomator(
<span style="color: #6a8759;"> "new UiSelector().textContains(</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">" </span>+
text + <span style="color: #6a8759;">"</span><span style="color: #cc7832;">\"</span><span style="color: #6a8759;">)"
</span> )<span style="color: #cc7832;">;
</span><span style="color: #cc7832;"> </span>} <span style="color: #cc7832;">catch</span>(NoSuchElementException e) {
<span style="color: grey;">//expected exception;
</span><span style="color: grey;"> </span>}
<span style="font-style: italic;">assertTrue</span>(element == <span style="color: #cc7832;">null</span>)<span style="color: #cc7832;">;
</span>}</span></pre>
<br />
If the driver fails to select the element, it will throw a NoSuchElementException, but we want that to happen here.<br />
<br />
Finally we run our feature suite by doing <span style="font-family: "courier new" , "courier" , monospace;">gradle cucumber</span>:<br />
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Executing tasks: [cucumber]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Configuration on demand is an incubating feature.</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:preBuild UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:preDebugBuild UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugAidl UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugRenderscript UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:checkDebugManifest UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:generateDebugBuildConfig UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:prepareLintJar UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:mainApkListPersistenceDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:generateDebugResValues UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:generateDebugResources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:mergeDebugResources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:createDebugCompatibleScreenManifests UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:processDebugManifest UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:splitsDiscoveryTaskDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:processDebugResources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:generateDebugSources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:javaPreCompileDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugJavaWithJavac UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugNdk NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugSources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:mergeDebugShaders UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:compileDebugShaders UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:generateDebugAssets UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:mergeDebugAssets UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:transformClassesWithDexBuilderForDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:transformDexArchiveWithExternalLibsDexMergerForDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:transformDexArchiveWithDexMergerForDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:mergeDebugJniLibFolders UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:processDebugJavaRes NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:validateSigningDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:packageDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:app:assembleDebug UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:compileJava NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:processResources NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:classes UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:jar UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:assemble UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:compileTestJava NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:processTestResources NO-SOURCE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:testClasses UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:compileCucumberJava</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:processCucumberResources UP-TO-DATE</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:cucumberClasses</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">:integration:cucumber</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Gradle now uses separate output directories for each JVM language, but this build assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Feature: Click the button</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Clicking buttons is clever</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Scenario: I see a button and click it. # features/hello.feature:4</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Given I have launched the application # BaseSteps.startApp()</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> When I click the "Click Me" button # BaseSteps.clickByText(String)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Then the "Click Me" is gone # BaseSteps.assertMissing(String)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">1 Scenarios (1 passed)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">3 Steps (3 passed)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">0m12.263s</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">BUILD SUCCESSFUL in 16s</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">30 actionable tasks: 2 executed, 28 up-to-date</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">1:18:07 PM: Task execution finished 'cucumber'.</span><br />
<br /></div>
Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0tag:blogger.com,1999:blog-9101311529221682232.post-76351881287920192682018-04-11T10:46:00.003-07:002018-04-11T11:02:32.953-07:00MQTT Sucks (First Post)So I saw that HackADay is having <a href="https://hackaday.com/2018/04/11/friday-hack-chat-talking-mqtt-with-the-community/">a chat about MQTT</a>.<br />
<br />
That seems as good as anything for an inaugural post on.<br />
<br />
TL;DR: MQTT sucks.<br />
<br />
The problem with the spec, as it is, is a simple one: there isn't enough spec there.<br />
<br />
<h3>
1. Authentication</h3>
<br />
With the spec basically having the equivalent of Basic Auth as your only option, every MQTT endpoint system ends up coming up with some idiot way to work around it. Sometimes it is an SSL key, sometimes it is a bearer token (put in either of the user/pass fields chosen at random). Unlike HTTP, MQTT is supposed to be about limited devices, but by leaving so much open to interpretation, you are basically burning firmware for a particular devices that is going to be nailed to a particular MQTT endpoint implementation.<br />
<br />
<h3>
2. Message Format</h3>
<br />
Much like authentication, the lack of any real delineation of message format in the spec means that everything does something different. If you want to use <a href="http://thingsboard.io/">ThingsBoard</a>, you need one channel hierarchy and message format for a device. If you want to use Google or Amazon's, you have to use their particular message format. Again, you are nailing your device to a particular endpoint implementation, or you end up having to do an MQTT -> MQTT transformation layer for anything that you want.<br />
<br />
<h3>
3. The Current Crop of Servers</h3>
<br />
As noted at the end of the last bit, unless you want to be nailed to one particular way of doing things, you end up having do build a proxy layer to adapt from one MQTT to another MQTT. Of course, though, none of the current endpoint implementations support doing this from <i>within</i> the server, so you have to cobble together something on your own, which is just ridiculous. Even Google and Amazon that already have powerful data pipeline tools don't let you accept a message and then transform it within their data pipeline tools; the message has to be perfectly formatted before they will receive it in the first damned place.<br />
<br />
We really need a new spec, or at least a clarification of the original that deals with the following:<br />
<br />
<ol>
<li>Authentication. AuthN should really be done with encryption keys, but the protocol needs a way for a client to request provisioning access from an endpoint with a pre-existing key, rather than provisioning a key on an endpoint and having to put it onto a device. </li>
<li>We need a standard format for at least a channel specification. That specification should include the concept of "<span style="font-family: "courier new" , "courier" , monospace;">this</span>" as a hierarchy param, an separate channels that imply sequenced data vs configuration or updates to static data. That is:<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">/clients/this/configuration</span> <- <span style="font-family: "courier new" , "courier" , monospace;">{ipAddress="10.10.10.10" name="weatherstation1"}</span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">/clients/this/sequence</span> <- <span style="font-family: "courier new" , "courier" , monospace;">{ "temperatureK"="300.15" }</span></li>
<li>Other standard channels could be defined, but it should be assume that each device should listen on /clients/this/configuration for provisioning and configuration updates.</li>
</ul>
Then when someone wants to subscribe to events from "weatherStation1" they can subscribe to <span style="font-family: "courier new" , "courier" , monospace;">/clients/[provisioned synthetic id]/sequence</span>.
</li>
<li>While MQTT as simple TCP and over websockets is already pretty standard, it makes no sense at all to me that IP Multicast isn't an option. Given the generally restrictive network environments lots of IoT type systems want to play in, it makes much more sense for a hub device on a given network environment to be able to grab messages out of "the air" and store and forward them onto a next leg network system.</li>
</ol>
MQTT isn't the only IoT protocol going on, but it is the one with the most traction right now. It is just too incompatible between environments to be REALLY useful. It wouldn't take much at all to get some standards around channel/message structure to solve most of these problems.<br />
<br />Robert "kebernet" Cooperhttp://www.blogger.com/profile/03336622901079453553noreply@blogger.com0