Generate A Public Key From A Private Key Python

My program generates public private keys, encrypts, decrypts, signs and verifies, while using AES for the bulk of the data for speed, and encrypts the random key with RSA. Many operations were chos. Mar 31, 2018 In this post I will demonstrate how to regenerate a public key from the corresponding private key that you still have. Generate public key and store into a file. It is a simple one liner command to generate a public key from a private key, so lets say our private key is named ‘user@myserver.key’ and we want to generate the public key.

2018-06-11T14:15:42Z

Posted by Miguel Grinberg under Authentication, Security, Python, Programming.

JSON Web Tokens offer a simple and powerful way to generate tokens for APIs. These tokens carry a payload that is cryptographically signed. While the payload itself is not encrypted, the signature protects it again tampering. In their most common format, a 'secret key' is used in the generation and verification of the signature. In this article I'm going to show you a less known mechanism to generate JWTs that have signatures that can be verified without having access to the secret key.

Quick Introduction to JSON Web Tokens (JWTs)

In case you are not familiar with JWTs, let me first show you how to work with them using Python with the pyjwt package. Create a virtual environment, and install pyjwt in it:

Now let's say you want to create a token that gives a user with id 123 access to your application. After you verify that the user has provided the correct username and password, you can generate a token for the user:

The jwt.encode() function has three arguments of which the most important is the first, containing the token payload. This is the information that you want stored in the token. You can use anything that can be serialized to a JSON dictionary as a payload. The payload is where you record any information that identifies the user. In the simplest case this is just the user id like in the example above, but you can include other user information such as a username, user roles, permissions, etc. Here is a more complex token:

Generate

As you can see, the more data you write in the payload, the longer the token is, because all that data is physically stored in the token. By looking at the resulting JWTs you may think that the data that you put in the tokens is encrypted, but this is actually incorrect. You should never write sensitive data in a JWT, because there is no encryption. This seemingly random sequence of characters that you see in these tokens is just generated with a simple base64 encoding.

In addition to user information, the payload of a JWT can include a few fields that apply to the token itself, and have a predefined meaning. The most useful of these is the exp field, which defines an expiration time for the token. The following example gives the token a validity period of 5 minutes (300 seconds):

Other predefined fields that can be included in the JWT are nbf (not before), which defines a point in time in the future at which the token becomes valid, iss (issuer), aud (audience) and iat (issued at). Consult the JWT specification if you want to learn more about these.

The second argument to jwt.encode() is the secret key. This is a string that is used in the algorithm that generates the cryptographic signature for the token. The idea is that this key must be known only to the application, because anyone who is in possession of this key can generate new tokens with valid signatures. In a Flask or Django application, you can pass the configured SECRET_KEY for this argument.

The last argument in the jwt.encode() call is the signing algorithm. Most applications use the HS256 algorithm, which is short for HMAC-SHA256. The signing algorithm is what protects the payload of the JWT against tampering.

The value returned by jwt.encode() is a byte sequence with the token. You can see in all the above examples that I decoded the token into a UTF-8 string, because a string is easier to handle.

Once your application generates a token it must return it to the user, and from then on, the user can authenticate by passing the token back to the server, which prevents the user from having to constantly send stronger credentials such as username and password. Using JWTs for authentication is considered more secure than usernames and passwords, because you can set an appropriate expiration time, and in that way limit the damage that can be caused in the case of a leak.

When the application receives a JWT from the user it needs to make sure that it is a legitimate token that was generated by the application itself, which requires generating a new signature for the payload and making sure it matches the signature included with the token. Using the first of the example tokens above, this is how the verification step is done with pyjwt:

The jwt.decode() call also takes three arguments: the JWT token, the signing key, and the accepted signature algorithms. Note how in this call a list of algorithms is provided, since the application may want to accept tokens generated with more than one signing algorithm. Note that while the algorithms argument is currently optional in pyjwt, there are potential vulnerabilities that can occur if you don't pass the list of algorithms explicitly. If you have applications that call jwt.decode() and don't pass this argument, I strongly advise you to add this argument.

The return value of the jwt.decode() call is the payload that is stored in the token as a dictionary ready to be used. If this function returns, it means that the token was determined to be valid, so the information in the payload can be trusted as legitimate.

Let's try to decode the token from above that had an associated expiration time. I have generated that token more than five minutes ago, so even though it is a valid token, it is now rejected because it has expired:

It is also interesting to see what happens if I take one of the tokens above, make a change to any of the characters in the string and then try to decode it:

So as you see, if jwt.decode() returns back a dictionary, you can be sure that the data in that dictionary is legitimate and can be trusted (at least as much as you are sure your secret key is really secret).

Using Public-Key Signatures with JWTs

A disadvantage of the popular HS256 signing algorithm is that the secret key needs to be accessible both when generating and validating tokens. For a monolithic application this isn't so much of a problem, but if you have a distributed system built out of multiple services running independently of each other, you basically have to choose between two really bad options:

  • You can opt to have a dedicated service for token generation and verification. Any services that receive a token from a client need to make a call into the authentication service to have the token verified. For busy systems this creates a performance bottleneck on the authentication service.
  • You can configure the secret key into all the services that receive tokens from clients, so that they can verify the tokens without having to make a call to the authentication service. But having the secret key in multiple locations increases the risk of it being compromised, and once it is compromised the attacker can generate valid tokens and impersonate any user in the system.

So for these types of applications, it would be better to have the signing key safely stored in the authentication service, and only used to generate keys, while all other services can verify those tokens without actually having access to the key. And this can actually be accomplished with public-key cryptography.

Public-key cryptography is based on encryption keys that have two components: a public key and a private key. As it name imples, the public key component can be shared freely. There are two workflows that can be accomplished with public-key cryptography:

  • Message encryption: If I want to send an encrypted message to someone, I can use that person's public key to encrypt it. The encrypted message can only be decrypted with the person's private key.
  • Message signing: If I want to sign a message to certify that it came from me, I can generate a signature with my own private key. Anybody interested in verifying the message can use my public key to confirm that the signature is valid.

There are signing algorithms for JWTs that implement the second scenario above. Tokens are signed with the server's private key, and then they can be verified by anyone using the server's public key, which is freely available to anyone who wants to have it. For the examples that follow I'm going to use the RS256 signing algorithm, which is short for RSA-SHA256.

The pyjwt package does not directly implement the cryptographic signing functions for the more advanced public-key signing algorithms, and instead depends on the cryptography package to provide those. So to use public-key signatures, this package needs to be installed:

The next step is to generate a public/private key set (usually called a 'key pair') for the application to use. There are a few different ways to generate RSA keys, but one that I like is to use the ssh-keygen tool from openssh:

The -t option to the ssh-keygen command defines that I'm requesting an RSA key pair, and the -b option specifies a key size of 4096 bits, which is considered a very secure key length. When you run the command you will be prompted to provide a filename for the key pair, and for this I used jwt-key without any path, so that the key is written to the current directory. Then you will be prompted to enter a passphrase to protect the key, which needs to be left empty.

When the command completes, you are left with two files in the current directory, jwt-key and jwt-key.pub. The former is the private key, which will be used to generate token signature, so you should protect this very well. In particular, you should not commit your private key to your source control, and instead should install on your server directly (you should keep a well protected backup copy of it, in case you ever need to rebuild your server). The .pub file will be used to verify tokens. Since this file has no sensitive information, you can freely add a copy of it on any project that needs to verify tokens.

The process to generate tokens with this key pair is fairly similar to what I showed you earlier. Let's first make a new token:

The main difference with the previous tokens is that I'm passing the RSA private key as the secret key argument. The value of this key is the entire contents of the jwt-key file. The other difference is that the algorithm requested is RS256 instead of HS256. The resulting token is longer, but otherwise similar to those I generated previously. Like the previous tokens, the payload is not encrypted, so also for these tokens you should never put sensitive information in the payload.

Now that I have the token, I can show you how it can be verified using the public key. If you are trying this with me, exit your Python session and start a new one, to make sure there is no trace of the private key in the Python context. Here is how you can verify the token above:

This example looks nearly identical to the previous ones, but the important fact is that we are ensuring this token is valid without access to any sensitive information. The server's public key presents no risk, so it can be freely shared with the world. And in fact, anybody would be able to verify the tokens that your application generates with this key. To prove this point, let me share with you my public key:

You can now take this public key and validate the token that I generated, and letting you validate the tokens does not introduce any security risks for me. I'm still the only person in the world that can generate new tokens.

Conclusion

I hope those of you who were using JWTs with the popular HS256 algorithm are now ready to introduce RS256 or any of the other public-key signature options available.

Let me know if you have any questions in the comment area below!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

41 comments

  • #1Ars said 2018-06-11T19:42:22Z

  • #2Miguel Grinberg said 2018-06-11T22:34:20Z

  • #3JM said 2018-07-06T00:47:09Z

  • #4Miguel Grinberg said 2018-07-06T05:37:07Z

  • #5Abdul Wahab van Reenen said 2018-07-30T10:21:35Z

  • #6Miguel Grinberg said 2018-07-30T21:02:35Z

  • #7SG said 2018-08-07T00:35:35Z

  • #8Miguel Grinberg said 2018-08-07T21:18:10Z

  • #9Mitch said 2018-08-19T22:08:06Z

  • #10stm said 2018-09-07T07:24:16Z

  • #11Miguel Grinberg said 2018-09-13T20:51:35Z

  • #12grex_e said 2018-10-17T23:52:59Z

  • #13Miguel Grinberg said 2018-10-18T14:19:33Z

  • #14grex_e said 2018-10-20T23:40:32Z

  • #15Vladyslav said 2018-11-01T09:58:18Z

  • #16yoni said 2018-11-10T00:18:03Z

  • #17Akshay said 2018-12-11T21:12:23Z

  • #18Miguel Grinberg said 2018-12-12T15:21:26Z

  • #19simi403 said 2018-12-19T18:24:52Z

    You generate a public/private key pair, then from that generate a Certificate Signing Request (which includes the public key), which you send to the CA. It then signs that public key included in the CSR producing the certificate which it sends back to you. As you can see, it’s very easy to generate SSH keys on Windows these days. Basically, the ssh-keygen command does all the work. If you find it difficult to understand how to add the public key to the server, look up your provider’s documentation. They always have a page that describes, in detail, how to do this. Generate public key for certificate https Public key vs private key. Public key is embedded in the SSL certificate and private key is stored on the server and kept secret. When a site visitor fills out a form with personal information and submits it to the server, the information gets encrypted with the public key to protect if from eavesdropping. Dec 01, 2015  To generate a public/private key file: Open puttygen.exe by double clicking on it: The standard install of puttygen.exe is in C:Program FilesPuTTY — but it is a standalone. Click the Generate button, and move the mouse around to generate randomness: PuTTYgen defaults to the desired RSA (SSH-2.

  • #20Miguel Grinberg said 2018-12-19T22:19:59Z

  • #21Kim said 2019-02-24T00:28:17Z

  • #22Miguel Grinberg said 2019-02-24T19:47:17Z

  • #23Saqib said 2019-04-12T10:10:24Z

  • #24Miguel Grinberg said 2019-04-12T18:34:58Z

  • #25Andy said 2019-08-17T13:19:30Z

Leave a Comment

In cryptocurrencies, a private key allows a user to gain access to their wallet. The person who holds the private key fully controls the coins in that wallet. For this reason, you should keep it secret. And if you really want to generate the key yourself, it makes sense to generate it in a secure way.

Here, I will provide an introduction to private keys and show you how you can generate your own key using various cryptographic functions. I will provide a description of the algorithm and the code in Python.

Do I need to generate a private key?

Most of the time you don’t. For example, if you use a web wallet like Coinbase or Blockchain.info, they create and manage the private key for you. It’s the same for exchanges.

Mobile and desktop wallets usually also generate a private key for you, although they might have the option to create a wallet from your own private key.

Python Generate Public Key From Private Key

So why generate it anyway? Here are the reasons that I have:

  • You want to make sure that no one knows the key
  • You just want to learn more about cryptography and random number generation (RNG)

What exactly is a private key?

Formally, a private key for Bitcoin (and many other cryptocurrencies) is a series of 32 bytes. Now, there are many ways to record these bytes. It can be a string of 256 ones and zeros (32 * 8 = 256) or 100 dice rolls. It can be a binary string, Base64 string, a WIF key, mnemonic phrase, or finally, a hex string. For our purposes, we will use a 64 character long hex string.

Why exactly 32 bytes? Great question! You see, to create a public key from a private one, Bitcoin uses the ECDSA, or Elliptic Curve Digital Signature Algorithm. More specifically, it uses one particular curve called secp256k1.

Now, this curve has an order of 256 bits, takes 256 bits as input, and outputs 256-bit integers. And 256 bits is exactly 32 bytes. So, to put it another way, we need 32 bytes of data to feed to this curve algorithm.

Generate A Public Key From A Private Key Python Florida

There is an additional requirement for the private key. Because we use ECDSA, the key should be positive and should be less than the order of the curve. The order of secp256k1 is FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, which is pretty big: almost any 32-byte number will be smaller than it.

Naive method

So, how do we generate a 32-byte integer? The first thing that comes to mind is to just use an RNG library in your language of choice. Python even provides a cute way of generating just enough bits:

Looks good, but actually, it’s not. You see, normal RNG libraries are not intended for cryptography, as they are not very secure. They generate numbers based on a seed, and by default, the seed is the current time. That way, if you know approximately when I generated the bits above, all you need to do is brute-force a few variants.

When you generate a private key, you want to be extremely secure. Remember, if anyone learns the private key, they can easily steal all the coins from the corresponding wallet, and you have no chance of ever getting them back.

So let’s try to do it more securely.

Generate A Public Key From A Private Key Python Code

Cryptographically strong RNG

Along with a standard RNG method, programming languages usually provide a RNG specifically designed for cryptographic operations. This method is usually much more secure, because it draws entropy straight from the operating system. The result of such RNG is much harder to reproduce. You can’t do it by knowing the time of generation or having the seed, because there is no seed. Well, at least the user doesn’t enter a seed — rather, it’s created by the program.

In Python, cryptographically strong RNG is implemented in the secrets module. Let’s modify the code above to make the private key generation secure!

That is amazing. I bet you wouldn’t be able to reproduce this, even with access to my PC. But can we go deeper?

Specialized sites

There are sites that generate random numbers for you. We will consider just two here. One is random.org, a well-known general purpose random number generator. Another one is bitaddress.org, which is designed specifically for Bitcoin private key generation.

Can random.org help us generate a key? Definitely, as they have service for generating random bytes. But two problems arise here. Random.org claims to be a truly random generator, but can you trust it? Can you be sure that it is indeed random? Can you be sure that the owner doesn’t record all generation results, especially ones that look like private keys? The answer is up to you. Oh, and you can’t run it locally, which is an additional problem. This method is not 100% secure.

Now, bitaddress.org is a whole different story. It’s open source, so you can see what’s under its hood. It’s client-side, so you can download it and run it locally, even without an Internet connection.

So how does it work? It uses you — yes, you — as a source of entropy. It asks you to move your mouse or press random keys. You do it long enough to make it infeasible to reproduce the results.

Are you interested to see how bitaddress.org works? For educational purposes, we will look at its code and try to reproduce it in Python.

Quick note: bitaddress.org gives you the private key in a compressed WIF format, which is close to the WIF format that we discussed before. For our purposes, we will make the algorithm return a hex string so that we can use it later for a public key generation.

Bitaddress: the specifics

Bitaddress creates the entropy in two forms: by mouse movement and by key pressure. We’ll talk about both, but we’ll focus on the key presses, as it’s hard to implement mouse tracking in the Python lib. We’ll expect the end user to type buttons until we have enough entropy, and then we’ll generate a key.

Bitaddress does three things. It initializes byte array, trying to get as much entropy as possible from your computer, it fills the array with the user input, and then it generates a private key.

Bitaddress uses the 256-byte array to store entropy. This array is rewritten in cycles, so when the array is filled for the first time, the pointer goes to zero, and the process of filling starts again.

The program initiates an array with 256 bytes from window.crypto. Then, it writes a timestamp to get an additional 4 bytes of entropy. Finally, it gets such data as the size of the screen, your time zone, information about browser plugins, your locale, and more. That gives it another 6 bytes.

After the initialization, the program continually waits for user input to rewrite initial bytes. When the user moves the cursor, the program writes the position of the cursor. When the user presses buttons, the program writes the char code of the button pressed.

Finally, bitaddress uses accumulated entropy to generate a private key. It needs to generate 32 bytes. For this task, bitaddress uses an RNG algorithm called ARC4. The program initializes ARC4 with the current time and collected entropy, then gets bytes one by one 32 times.

This is all an oversimplification of how the program works, but I hope that you get the idea. You can check out the algorithm in full detail on Github.

Doing it yourself

For our purposes, we’ll build a simpler version of bitaddress. First, we won’t collect data about the user’s machine and location. Second, we will input entropy only via text, as it’s quite challenging to continually receive mouse position with a Python script (check PyAutoGUI if you want to do that).

That brings us to the formal specification of our generator library. First, it will initialize a byte array with cryptographic RNG, then it will fill the timestamp, and finally it will fill the user-created string. After the seed pool is filled, the library will let the developer create a key. Actually, they will be able to create as many private keys as they want, all secured by the collected entropy.

Initializing the pool

Here we put some bytes from cryptographic RNG and a timestamp. __seed_int and __seed_byte are two helper methods that insert the entropy into our pool array. Notice that we use secrets.

Seeding with input

Here we first put a timestamp and then the input string, character by character.

Generating the private key

This part might look hard, but it’s actually very simple.

First, we need to generate 32-byte number using our pool. Unfortunately, we can’t just create our own random object and use it only for the key generation. Instead, there is a shared object that is used by any code that is running in one script.

What does that mean for us? It means that at each moment, anywhere in the code, one simple random.seed(0) can destroy all our collected entropy. We don’t want that. Thankfully, Python provides getstate and setstate methods. So, to save our entropy each time we generate a key, we remember the state we stopped at and set it next time we want to make a key.

Second, we just make sure that our key is in range (1, CURVE_ORDER). This is a requirement for all ECDSA private keys. The CURVE_ORDER is the order of the secp256k1 curve, which is FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.

Finally, for convenience, we convert to hex, and strip the ‘0x’ part.

In action

Let’s try to use the library. Actually, it’s really simple: you can generate a private key in three lines of code!

You can see it yourself. The key is random and totally valid. Moreover, each time you run this code, you get different results.

Conclusion

Generate A Public Key From A Private Key Python Pdf

As you can see, there are a lot of ways to generate private keys. They differ in simplicity and security.

Generating a private key is only a first step. The next step is extracting a public key and a wallet address that you can use to receive payments. The process of generating a wallet differs for Bitcoin and Ethereum, and I plan to write two more articles on that topic.

If you want to play with the code, I published it to this Github repository.

I am making a course on cryptocurrencies here on freeCodeCamp News. The first part is a detailed description of the blockchain.

Generate A Public Key From A Private Key Python Free

I also post random thoughts about crypto on Twitter, so you might want to check it out.