What is the key scheme used in the hypercore protocol? - public-key-encryption

What is the key scheme used in the hypercore protocol?
I didn't find a quick/good answer on searching so adding the question here.

It is ed25519
From here:
Public key. An ed25519 public key unique to this Dat, used by the
author to create and update data within it. The public key enables you
to discover other peers who have the data and verify that the data was
not corrupted or tampered with as it passed through the network.

Related

ECDSA Public Key format analysis

I am having a blockchain application set up with Hyperledger Fabric and I want to get the public key from the caller inside the chaincode.
I use golang for the chaincode and I have managed to retrieve from the caller the certificate X509 and from that, the PublicKey in an unreadable format.
Since in the documentation says that this field (Public Key) from the Certificate structure is of type any, I am just setting it into a string using Sprintf.
And this is the output:
&{{0xc000624040} 110006408051620173868267843413892792474981993401645508314118747530986647833211 30374913908846219606392346947456049633394351895879251216926799242930673498259}
I can understand that this might be the encoding of the ECDSA signature and that this might be the actual public key. But, I am not able to clearly understand what does this exactly represent and how can I convert into a hash.
If I hash it directly, the Public Key that I have retrieved from the node js application where I used KEYUTIL to parse it from the users certificate, is different than the result that is being produced here. Why is this happening? What should be hashed in order to be the same?
Any recommendations to read something or any tip would be helpful. Thank you.
After, discussion on the comments bellow, it has been found how to properly format the Public Key so all values of the ECDSA key can be visible.
Using the KEYUTIL library in the node js there is the function of 'getKey' which retrieves the Public Key of the user and in there, there is a field called: pubkeyHex
This is stated:
#param pubkeyHex hexadecimal string of public key for that.
And what is is beeing displayed is: 04f3356ba599db0542d0cd5beeb6ac844aa1d194f787a9d9b1dbee3f034215ca7b4327 978ef9122386f73280c1dd7865eb2d1d7b27dcff6c23f20423ea81c13893
I thought that this is a hash as this looks like it. But, from the name of the function might be something else (hex).
So, the above is the representation of the whole Public Key in this format. And here comes the next question on how this might be produced.

Can a rotated certificate decrypt a value that was encrypted before the rotation?

I understand the purpose of rotating certificates. It is security.
But I wonder if a rotated certificate can decrypt a value that was encrypted before the rotation?
If not, does "rotation-software" help you with decrypting and reencrypting all the current encrypted values you have?
Regards Hans
It depends on one thing - did you change the public and private keys when you rotated the cert?
Remember, a cert is just a host for a public key, or more accurately, a way to bind an identity (CN=foo.com) to a public key.
When you roll a cert, you have an option: do you roll the keys as well or do you just re-issue a new cert with the same key?
If you roll the keys, then no, you can no longer use the new cert to perform crypto operations on data manipulated by the old cert.
If you just reissue the cert and don't roll the keys, then you're ok.
I hope that helps.

In Polkadot-js is there a method to create HD wallet addresses

I am using Polkadot-js api and wondered if there is an API to generate hierarchical deterministic wallet addresses from a given seed?
I see that there is some mention of soft and hard derivation paths, in Substrate's subkey documentation but do not know if this has been ported to Polkadot-js or how it could be invoked.
SURI are supported by Polkadot-js using createFromUri or addFromUri to create or add a new account to your keyring.
You can import keyring from '#polkadot/ui-keyring' and then use it:
keyring.createFromUri(`${phrase.trim()}${derivePath}`, {}, pairType)
Here is the definition of the function
edit: The derive path could be any combination of /[soft], //[hard], that can be repeated and don't have to be in this order, on top of this, you can have an additional ///[password].
So you can pass as argument to the createFromUri function, something like:[mnemonic phrase]//Kusama//DAO/1 or [mnemonic phrase]//MyMainFunds/0///ThisIsMyPassword.

How to get a SecIdentityRef from a SecCertificateRef and a SecKeyRef

Here's what I've already tried:
First idea was, just put both into an array, use that array with kSecUseItemList, so keychain calls will operate only on the items in this array, not on real keychains and then get the identity like this:
NSDictionary * searchQuery = #{
(__bridge id)kSecClass:(__bridge id)kSecClassIdentity,
(__bridge id)kSecUseItemList:#[(__bridge id)key, (__bridge id)cert],
(__bridge id)kSecReturnRef:#YES
};
CFTypeRef foundItem = NULL;
OSStatus copyStatus = SecItemCopyMatching(
(__bridge CFDictionaryRef)searchQuery, &foundItem
);
Turned out that this doesn't work. To quote from the docs:
#constant kSecUseItemList
Specifies a dictionary key whose value is a
CFArray of items. If provided, this array is treated as the set of
all possible items to search, or add if the API being called is
SecItemAdd. The items in this array may be of type SecKeyRef,
SecCertificateRef, SecIdentityRef, or CFDataRef (for a persistent
item reference.) The items in the array must all be of the same
type. When this attribute is provided, no keychains are searched.
Well, they are not of the same type, so this cannot work.
My second attempt was to add both items to keychain (using SecItemAdd()), which works as expected, then find the certificate (using SecItemCopyMatching()) which also succeeds and finally getting my identity using:
SecIdentityRef identity = NULL;
OSStatus copyStatus = SecIdentityCreateWithCertificate(NULL, cert, &identity);
But that fails with errKCItemNotFound.
Looking at the items in Keychain Access app, the certificate and the private key are both there, they are both correct but they are not displayed as forming an Identity (they are not listed under "My Certificates", the cert is only listed under "Certificates" and the key under "Keys").
Okay, what am I doing wrong or what important step am I missing?
If I export the key to PKCS#8 and the cert to DER notation, then use openssl on command line to combine both into a PKCS#12 file and import that file with Keychain Access, then they are displayed as an Identity in keychain access and this identity also works correctly (so the private key is really the correct key for the public key in the cert). But this is not really an option, as my code must not rely on OpenSSL and would ideally be portable to iOS.
As far as I understood the documentation, the identity matching is done by matching public key hashes, so that could be related to my problem. How would the system know the hash of the public key for me SecKeyRef, which is only a raw private RSA key?
The docs also say that I can add a SecIdentityRef directly with SecAddItem(), in which case I guess everything would probably work as expected (the identity itself cannot be added, the cert and the private key will be added, but I assume the identity binding will be okay when adding them that way), but that sounds like a chicken-egg-problem, since how would I get that identity reference in the first place?
I cannot understand why there is no SecCreateIdentity(...) function that simply takes a SecCertificateRef and SecKeyRef on input and returns a SecIdentityRef on output.
Update
Here's some interesting info I found in SecKey.h:
#constant kSecKeyLabel type blob, for private and public keys
this contains the hash of the public key. This is used to
associate certificates and keys. Its value matches the value
of the kSecPublicKeyHashItemAttr of a certificate and it's used
to construct an identity from a certificate and a key.
For symmetric keys this is whatever the creator of the key
passed in during the generate key call.
This value is not correctly set. The public key in the certs hashes to 0x966C57... but my private key contains 0x097EAD... and this looks like the hash of the private key itself. I will try if I can somehow set this value to the correct one.
Update 2
That seems to be another dead end. When I try to set kSecAttrApplicationLabel with SecKeyUpdate() on a key prior to adding it to keychain, I get errKCItemNotFound, which is expected, as the documentation says:
A SecKeyRef instance that represents a key that is stored in a keychain
can be safely cast to a SecKeychainItemRef for manipulation as a
keychain item. On the other hand, if the key is not stored in a
keychain, casting the object to a SecKeychainItemRef and passing
it to Keychain Services functions returns errors.
Fair enough. So I first add the key, then retrieve it back from keychain and finally try to update kSecAttrApplicationLabel, but this fails as well, this the error is errKCNoSuchAttr.
Oh, in case anyone wonders why I'm updating kSecAttrApplicationLabel when I said the attribute is named kSecKeyLabel in my first update: The kSecKeyLabel is an enumeration value of the old attribute enumerations that Apple used with various API calls that have all been deprecated. The new API calls (like SecItemUpdate()) work with dictionaries and as using enum values as dictionary keys is a bit ugly, Apple defined a new set of dictionary keys that are CFStringRef.
#constant kSecAttrApplicationLabel Specifies a dictionary key
whose value is the key's application label attribute.
This is different from the kSecAttrLabel (which is intended to be
human-readable). This attribute is used to look up a key
programmatically; in particular, for keys of class
kSecAttrKeyClassPublic and kSecAttrKeyClassPrivate,
the value of this attribute is the hash of the public key.
This item is a type of CFDataRef.
Legacy keys may contain a UUID in this field as a CFStringRef.
So this seems to be the correct attribute to update, doesn't it? Except that the error implies no such attribute exists for the item. Even though the same header file explicitly lists this attribute as a possible attribute for SecKeyRef items:
kSecClassKey item attributes:
kSecAttrAccess (OS X only)
kSecAttrAccessControl
kSecAttrAccessGroup
(iOS; also OS X if kSecAttrSynchronizable specified)
kSecAttrAccessible
(iOS; also OS X if kSecAttrSynchronizable specified)
kSecAttrKeyClass
kSecAttrLabel
kSecAttrApplicationLabel
[... and so on ...]
Update 3
The first answer I got suggested to use SecItemCopyMatching() instead, however, please understand that this code:
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching(
(__bridge CFDictionaryRef)#{
(__bridge id)kSecClass:(__bridge id)kSecClassIdentity,
(__bridge id)kSecMatchItemList:#[(__bridge id)cert],
(__bridge id)kSecReturnRef:#YES
}, &result
);
is really functional identical to his code:
SecIdentityRef result = NULL;
OSStatus status = SecIdentityCreateWithCertificate(
NULL, cert &result
);
The later one is just the older API call (older, but not deprecated) from the time where keychain access was limited to working with Sec...Ref CoreFoundation "objects" (Apple's attempt to mimic a bit of OO in pure C), whereas the first one is the newer API where you usually only work with dictionary representation of keychain items (as that casts toll-free to Obj-C, you just need some bridging casts when you use ARC) but where you also have the choice to fall back to CoreFoundation "objects" (when using attributes like e.g. kSecMatchItemList, kSecUseItemList, or kSecReturnRef). I'm' actually rather sure that in fact there's just one real API and the other one is just implemented on top of the other one (depending which one on top of which one, the newer one may just exist for convenience or the older one was just kept for backward compatibility).
The trick is to export the in-memory key first and then re-import it directly to the keychain instead of just adding it there. See the code below (careful, it's C++):
static OSStatus AddKeyToKeychain(SecKeyRef privateKey, SecKeychainRef targetKeychain)
{
// This is quite similar to pal_seckey's ExportImportKey, but
// a) is used to put something INTO a keychain, instead of to take it out.
// b) Doesn't assume that the input should be CFRelease()d and overwritten.
// c) Doesn't return/emit the imported key reference.
// d) Works on private keys.
SecExternalFormat dataFormat = kSecFormatWrappedPKCS8;
CFDataRef exportData = nullptr;
SecItemImportExportKeyParameters keyParams = {};
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = CFSTR("ExportImportPassphrase");
OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &exportData);
SecExternalFormat actualFormat = dataFormat;
SecExternalItemType actualType = kSecItemTypePrivateKey;
CFArrayRef outItems = nullptr;
if (status == noErr)
{
status =
SecItemImport(exportData, nullptr, &actualFormat, &actualType, 0, &keyParams, targetKeychain, &outItems);
}
if (exportData != nullptr)
CFRelease(exportData);
CFRelease(keyParams.passphrase);
keyParams.passphrase = nullptr;
if (outItems != nullptr)
CFRelease(outItems);
return status;
}
The code has been taken from here.
The answer from #bartonjs really solves my problem, I just want to provide some extra helpful information here, as it is not very obvious why it solves the problem:
First of all, please note that security objects can either exist only in memory or they can exist in memory backed up by keychain storage. Every security object has data (the actual data that defines the object) and metadata (additional information that describes the data). But only objects backed up by keychain storage can have metadata as the metadata attributes are defined as part of the keychain API and not as part of the object API. If objects are not stored in a keychain, they simply cannot have metadata. See Update 2 of my question.
The public key hash, which is required to match private keys to their certificates, is stored within the metadata. So a SecKeyRef not backed up by keychain storage cannot have such a hash. Generating an identity (SecIdentityRef) with a key not stored in a keychain is thus simply not possible. The certificate doesn't have to be stored in a keychain but the key has.
So far I was just adding my key using SecItemAdd(), which seems to do exactly what the name implies, it just adds the item to keychain, and it only does what the name implies, so it won't do anything but adding the item to keychain as is. If the item already has a public key hash, it will also have a public key hash when being added to a (new/different) keychain, but only items already within keychains can have this attribute. The result was an item not having a correct public key hash set and this is the cause of all my problems.
Now my code uses the SecItemImport() function, which is a lot more powerful, as an "import" may require a lot more steps than just adding something keychain. Apparently this import function will also make sure that the public key hash in the meta data is correctly populated when importing the item. To make this import possible, my new code first needs to export the existing key and so it can then re-import the key directly into the desired keychain.
Update
Maybe interesting to know, there exists a function with the following syntax:
SecIdentityRef SecIdentityCreate(
CFAllocatorRef allocator,
SecCertificateRef certificate,
SecKeyRef privateKey
);
that works exactly the way I was desiring it. ffmpeg is actually using it. But this is private API, you must not use it if you plan to submit your software to any app store (using private API will have your software rejected).

How to store a RijndaelManaged generated KEY and IV in the database for later use?

Let me start by saying....yes I have read tons of posts on here in the last two days. No, I don't know anything about encryption, so don't bother...with the you shouldn't playing with fire comments..
I have a asp.net MVC3 application and want to encrypt the photos that users upload using a key for each user. I want to save this key and use it for any further uploads by the same user and for the decryption. (Although, I suppose I could store a key for each photo instead, not really relevant to this problem but...)
I started with the code from here:
http://www.codeproject.com/Articles/33344/Photo-Video-Viewer-with-Encryption-Capability
It works fine. It encrypts the photos and decrypts them to a new file and all is well. The "on the fly version" also works and returns a MemoryStream that I can use for my WebImage. However, as you can see the example is encrypting and decrypting in one pass and the key is a global variable (I don't know what it was, I just used the autogenerated key when I tested.
So, I need someone to tell me how to store the generated key (and IV I guess??? Told you I know nothing about enc...) in the database for each user and then pull that (those) value(s) back out to use for on the fly decryption. I am not going to bother to post all my code yet, as it is almost identical to what is on the above site.
I read another post on here and it said to use:
string x = Convert.ToBase64String(RMCrypto.Key);
Then when I wanted to decrypt I used:
RMCrypto.Key = Convert.FromBase64String(x);
I stored both the key and IV in this manner in my SQL DB, but when I pull the values and try to decrypt I get an error that the data is not the expected length.
Maybe I'm totally off base or maybe it's three lines of code... Please let me know if more information is needed.
Thanks!
You can store them as binary columns values. That being said the protection of encrypted data is only as safe as the key protecting it. In other words storing the key with the data your protecting is sorta fox guarding the hen house kind of thing. But if your not worried about it for things like PCI compliance then it's probably not too bad a deal.
How you might convert it to binary
private void UpdateDb(byte[] key, byte[] iv)
{
using (SqlConnection db = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("insert into (key, iv) values (#key, #iv)", db))
{
db.Open();
cmd.Parameters.AddWithValue("#key", key);
cmd.Parameters.AddWithValue("#iv", iv);
cmd.ExecuteNonQuery();
}
}
To make it a little harder you could generate a new key and IV for each record (image) your protecting and then store that so that if someone we're to get one key at least they wouldn't have all your data wide open. Good luck!
You should store the actual byte arrays (yes; both key and IV) in the database.
You don't need strings at all.

Resources