I trying to accomplish step (2) in the following way programmatically:
1. openssl genrsa -out signing.pem 2048
2. openssl rsa -in signing.pem -outform PEM -pubout -out signing.pub.pem
Following is a simple function which reads the private key and tries to extract the public key.
But, I am facing difficulty in matching the 2nd step, as the programmatically generated public key is different from the openssl CLI based public key, I am sure there must some mistake, Please, help me.
Thanks
func main() {
priv, err := ioutil.ReadFile("signing.pem")
block, _ := pem.Decode([]byte(priv))
if block == nil || block.Type != "RSA PRIVATE KEY" {
log.Fatal("failed to decode PEM block containing public key")
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
log.Fatal(err)
}
publicKeyDer := x509.MarshalPKCS1PublicKey(&pub.PublicKey)
pubKeyBlock := pem.Block{
Type: "PUBLIC KEY",
Headers: nil,
Bytes: publicKeyDer,
}
pubKeyPem := string(pem.EncodeToMemory(&pubKeyBlock))
fmt.Println(pubKeyPem)
}
IN case anyone wants to check the code and play around then here's the link:
https://play.golang.org/p/rKerkh-31KI
Use MarshalPKIXPublicKey
publicKeyDer, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
if err != nil {
log.Fatal(err)
}
Instead of
publicKeyDer := x509.MarshalPKCS1PublicKey(&key.PublicKey)
Playground
Related
I am planning to generate following pin-sha256 :
Public-Key-Pins:
pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=";
pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=";
max-age=5184000; includeSubDomains;
report-uri="https://www.example.org/hpkp-report"
So that i can keep in IIS for security reasons as below:
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="Public-Key-Pins" value="pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubDomains" />
</customHeaders>
</httpProtocol>
...
</system.webServ
But my server lacks open ssl and take long time to install because of process issues.
Could you please let me know is there any alternative without these openssl that i can generate pins?
See this link for more details
These are the pin generation commands, i need to do this without openssl , is it possible?
openssl rsa -in my-rsa-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
Here is an example of the openssl command chain above converted into openssl API calls that output the base64 result to the screen.
The main calls are
PEM_read_bio_PrivateKey to read in the private key in PEM format.
i2d_RSA_PUBKEY_bio to convert the RSA public key into DER format
EVP_Digest to create the SHA256 digest (hidden behind the BIO_f_md BIO usage)
BIO_f_base64 BIO usage to convert the digest into base64 format
There are lots of ways to do the same job using variations of the above OPENSSL API's depending on your situation.
Below is a C++ usage of the OpenSSL C API. You can easily strip the C++ bits if required.
template<typename T, typename D>
std::unique_ptr<T, D> make_handle(T* handle, D deleter)
{
return std::unique_ptr<T, D>{handle, deleter};
}
bool load_rsa_private_key_and_base64_sha256_hash_public_key()
{
// load rsa private key in PEM format
auto bio = make_handle(BIO_new_file("privatekey.pem", "rb"), BIO_free);
if(!bio) return false;
auto const key = make_handle(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, (void*)("password")), EVP_PKEY_free);
bio.reset();
if(!key) return false;
// extract private key from loaded certificate
auto const rsa = EVP_PKEY_get0_RSA(key.get());
if (!rsa) return false;
// setup sha256 bio chain
auto const bmd = make_handle(BIO_new(BIO_f_md()), BIO_free);
if(!bmd) return false;
if (!BIO_set_md(bmd.get(), EVP_sha256())) return false;
auto const null_bio = make_handle(BIO_new(BIO_s_null()), BIO_free);
auto in = BIO_push(bmd.get(), null_bio.get());
// write RSA Public Key into DER format to the SHA256 digest BIO chain
i2d_RSA_PUBKEY_bio(in, rsa);
// extract the SHA256 digest
auto mdtmp = BIO_find_type(in, BIO_TYPE_MD);
if (!mdtmp) return false;
std::array<char, EVP_MAX_MD_SIZE> buffer;
auto const length = BIO_gets(mdtmp, buffer.data(), buffer.size());
if(length <= 0) return false;
// convert the digest to base64 and output to the stdio
auto const b64 = make_handle(BIO_new(BIO_f_base64()), BIO_free);
auto const bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
auto out = BIO_push(b64.get(), bio_out);
BIO_write(out, buffer.data(), length);
BIO_flush(out);
return true;
}
I am trying to establish a TLS connection by providing a tls.Config struct containing a Rand field that should always return the same int when calling their Read method, cf. the docs here: https://golang.org/pkg/crypto/tls/#Config
I've written this builder:
func newZeroRand() *rand.Rand {
return rand.New(rand.NewSource(0))
}
And a test to make sure that rand.Rand is always returning the same int when Read is invkoed multiple times, notice the different input params "foo" and "bar" providing the same output:
func TestPredictableZeroRandGenerator(t *testing.T) {
zeroRand := newZeroRand()
firstNum, err := zeroRand.Read([]byte("foo"))
if err != nil {
t.Error(err)
}
secondNum, err := zeroRand.Read([]byte("bar"))
if err != nil {
t.Error(err)
}
// fmt.Printf("firstNum %d secondNum %d \n", firstNum, secondNum)
if firstNum != secondNum {
t.Error(fmt.Sprintf("This is not a predictable zero random generator! The first number is: %d the second number is: %d", firstNum, secondNum))
}
}
Using that previously defined newZeroRand() I was expecting to generate always the same SSL key inside the file same-key.log when providing the TLS configuration like this:
func tlsConfig() (*tls.Config, error) {
w, err := os.OpenFile("same-key.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return nil, err
}
tlsConfig := tls.Config{
Rand: newZeroRand(),
KeyLogWriter: w,
}
return &tlsConfig, nil
}
But for multiple executions I get different file contents. I may be misunderstanding the details here: https://golang.org/pkg/crypto/tls/#example_Config_keyLogWriter because when I open those files same-key.log after each execution
then I find the structure described here in the NSS Key Log Format from Mozilla: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
CLIENT_RANDOM <FIRST_LONG_ID> <SECOND_LONG_ID>
where:
<FIRST_LONG_ID> is always the same
<SECOND_LONG_ID> is changing after each execution <-- why this is happening?
When providing a key file same-key.log for a batch of packets from a different execution, then Wireshark is not able to decrpyt them!
I may be misunderstanding some internals about SSL cryptography here and I was wondering if I should also provide the certificates in the configuration struct? How could I generate these certificates?
Afaik when using certificates on top of the key there should be a piece of information coming from the other side at runtime, so then I can not decrypt the stream of packets if I don't have that information. This is why I thought certificates are not needed if I want to use Wireshark to decrypt those packets.
Otherwise I am not sure how could I force the TCP connection to always encrypt/decrypt the packets with the same key?
Edit:
As pointed out by #peter in his answer I was asserting on the length of the input byte slice rather than the actual "deterministic-random value".
I came out with this Read implementation for the tls.Config struct:
type debugRand struct {}
func (dr *debugRand) Read(p []byte) (n int, err error) {
for i := range p {
p[i] = byte(0)
}
return len(p), nil
}
func newZeroRand() *debugRand {
return &debugRand{}
}
This is setting to 0 all the elements of the input slice.
However I still generate SSL keys which have different <SECOND_LONG_ID> values for different executions.
Is it possible at all to get Wireshark re-using SSL keys on different TLS connections when analysing those encrypted TCP packets?
You are using Read wrong. Your test doesn't test what you think it does. firstNum and secondNum are both 3 because you are reading three random bytes; because you are passing byte slices of length three. You never check the actual random bytes though.
How can I implement the effect of following command in Objective-C?
openssl rsa -in mykey.pem -pubout > mykey.pub
I'm able to generate a private key in pem format.
Here is the code I use to read the private key into a openssl RSA object.
BIO* bpPrivate = nil;
NSString *filePath = .....
const char *path = [filePath UTF8String];
bpPrivate = BIO_new_file(path, "r");
_rsa = PEM_read_bio_RSAPrivateKey(bpPrivate, NULL, 0, NULL);
I want to extract the public key from the private key.
In memory, there is no notion of ASN.1, DER, PEM or other encodings. A RSA key uses the same structure for both the public and private key. For a public key, some fields are not used. If you are interested in the fields, then visit PKCS #1 or RFC 3447.
So, given an RSA*, all you need to do is call PEM_write_bio_RSAPublicKey (even with a private key). You can also use PEM_write_RSAPublicKey (even with a private key). See pem(3) for all the read and write functions.
You can also accomplish it the long way by way of RSAPublicKey_dup. It will take a priavte key (i.e., a RSA*) and return a public key (i.e., a RSA*). But its kind of an unnecessary step for the most part. It might be useful to keep the key in memory, if you have that requirement.
RSA* privKey = NULL;
RSA* pubKey = NULL;
BIGNUM* exp = NULL;
privKey = RSA_new();
ASSERT(privKey != NULL);
exp = BN_new();
ASSERT(exp != NULL);
rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);
rc = RSA_generate_key_ex(privKey, 1024, exp, NULL);
ASSERT(rc == 1);
pubKey = RSAPublicKey_dup(privKey);
ASSERT(pubKey != NULL);
RSA_print_fp(stdout, pubKey, 0);
if(pubKey) {
RSA_free(pubKey);
}
if(privKey) {
RSA_free(privKey);
}
if(exp) {
BN_free(exp);
}
The RSA_print_fp results in:
$ ./t.exe
Public-Key: (1024 bit)
Modulus:
00:c3:30:67:d9:11:59:9b:85:7a:1a:95:fa:fd:c0:
dd:cd:21:d6:41:6b:16:70:c2:57:9a:f2:d2:bd:3b:
c0:02:7b:6a:ab:7f:13:a7:53:2f:31:10:08:3a:62:
28:40:5f:82:19:23:f6:0f:78:f5:e3:e4:19:a1:b4:
73:65:35:10:db:17:28:41:42:ba:df:8c:18:3b:d8:
62:52:65:61:0e:cd:60:28:c9:75:a8:5b:46:a4:89:
db:78:89:49:87:5d:7f:ce:d0:44:c4:fd:4a:74:66:
d4:46:21:c1:89:97:28:de:43:e9:94:50:f1:36:85:
a7:ef:6c:6d:6f:5d:78:00:67
Exponent: 65537 (0x10001)
You can add a call to PEM_write_RSAPublicKey:
FILE* file = fopen("rsa-pub.pem", "w");
ASSERT(file != NULL);
rc = PEM_write_RSAPublicKey(file, pubKey);
Then:
$ ./t.exe
$ cat rsa-pub.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMb2jIVcTttHRqG9szv3CFZ742l7LxnVoM6oOfQXNOwabh+GB4Srf4IA
XRcGan7cj1DShnoPw9fp3IeuAUerk3xz8yPXCw09dLwrFcsmItLVnSLoRtpHnxN5
30Wd5vKpvKTLIQnurGo05s911ukFJeGo2y2OjSnTiQcJLUdt497tAgMBAAE=
-----END RSA PUBLIC KEY-----
I've put together a golang func that takes an uploaded file and saves it to folder.
Just before os.Create() I am getting the following error :
http: panic serving [::1]:64373: runtime error: index out of range
My golang function is:
func webUploadHandler(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file") // the FormFile function takes in the POST input id file
if err != nil {
fmt.Fprintln(w, err)
return
}
defer file.Close()
// My error comes here
messageId := r.URL.Query()["id"][0]
out, err := os.Create("./upload/" + messageId + ".mp3")
if err != nil {
fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
return
}
defer out.Close()
// write the content from POST to the file
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
}
fmt.Fprintf(w,"File uploaded successfully : ")
fmt.Fprintf(w, header.Filename)
}
any ideas? much appreciate
You should at least check if r.URL.Query()["id"] has actually one element.
If len(r.URL.Query()["id"]), you could consider not accessing the index 0.
Easier, Ainar-G suggests in the comments to use the Get() method
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns the empty string.
To access multiple values, use the map directly.
I need to sign a message for submission to a remote service (over a websocket). To do this, I need to structure a private key based on an integer (my user id) and a passphrase (a base64 encoded string)., hashed using SHA224. I'm using golang, and crypto/ecdsa for this with accompanying packages for byte encoding etc.
Here's the documentation I have:
Signatures use an Elliptic Curve Digital Signature Algorithm (ECDSA)
encoded message containing: user ID, Server Nonce, Client Node and
Private key. Private keys are generated hashing your user ID and your
password with SHA224.
Here's my func:
func NewKey(userId int64, pass string) (prKey ecdsa.PrivateKey) {
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, userId)
passArr := []byte(pass)
sha := sha256.New224()
sha.Write(buf.Bytes())
sha.Write(passArr)
sum := sha.Sum(nil)
var in int64
reader := bytes.NewReader(sum)
err := binary.Read(reader, binary.BigEndian, &in)
if err != nil {
log.Fatal(err)
}
prKey.D = big.NewInt(in)
prKey.PublicKey.Curve = elliptic.P224()
return prKey
}
My intent with this func is that it:
Hashes the userId and pass correctly in a []byte using SHA224.
Reads that into an int64 which is then used as the private key
Constructs an instance of ecdsa.PrivateKey and corresponding ecdsa.PublicKey correctly
Returns said key for use in ecdsa.Sign() function calls
I then sign another message which consists of a userId (integer), and two nonces.
Here's how I sign my message:
key := NewKey(userId, pass) // the above func
msg := sha256.New224().Sum([]byte(userId + srNonce + clNonce))
r, s, err := ecdsa.Sign(rand.Reader, &key, msg)
sig := []string{enc(r.String()), enc(s.String())}
Questions:
Is my NewKey func correct?
The r and s components are very large - presumably because I'm using int64. Could this be an issue?
Is the line sha256.New224().Sum([]byte(userId + pass)) "correct" for hasing those two items?
How can I create my private key correctly (assuming it's wrong) and subsequently sign the message?
I'm very new to ECDSA and have basic crypto knowledge in general.
To answer my own questions:
Is my NewKey func correct?
No.
The r and s components are very large - presumably because I'm using int64. Could this be an issue?
They should be large.
Is the line sha256.New224().Sum([]byte(userId + pass)) "correct" for hashing those two items?
It's correct insofar as I'm passing it a []byte.
How can I create my private key correctly (assuming it's wrong) and
subsequently sign the message?
The key requires a big.Int, so using the following should suffice assuming the hash is correct:
key := new(big.Int).SetBytes(sum)