Are encrypted strings URL Safe? - url

I have a need to encrypt a part of the URL e.g https://www.example.com/resource/{resourceid}.
The resourceid is the element that I want to encyrpt as it may be a sensitive piece of information.
Before returning this URL to the clients, we want to encrypt the resourceid and on the way back (from the client on a subsequent request) we will decrypt the resourceid before processing.
The original resourceid is a string (alphanumeric characters). They are not super-secret, the intent is to make them an "opaque" string before returning them to the caller.
I am unable to figure out if the result of an encryption (symmetric key is what I am after) is URL safe? I can encrypt the resource ID and then do a URL encoding on top and do the reverse on the way back.
However, if the encryption outcome is already URL safe, i won't need to worry about it. I am unable to locate any information that states whether the outcome of an encryption function is URL safe or not.
Any help or pointers would be helpful.

Related

how do you request a new downloadUrl from graph-onedrive?

In my C# code with the Graph SDK, I am testing "download large file" with a method generously provided here: Download large files from OneDrive using Microsoft Graph SDK
However, even though I explicitly request the DriveItem from the service just prior to calling this method (which then uses the downloadUrl from the AdditionalData in the DriveItem), I am getting a response indicating JWT Token Expired.
I assume this token is embedded in the pre-authenticated downloadUrl. Further, I theorize that this token is either single-use or it expires relatively quickly...both reasons for me to explicitly request the DriveItem just before attempting to utilize that URL.
How do I ensure that the service is sending me back a "fresh" downloadUrl? Are there some no-cache headers or something I should explicitly include in my DriveItem request?
As mentioned, even though I have the DriveItem object local, I am explicitly re-fetching it from the service to ensure I have the latest properties, and a new downloadUrl. (But this is not working.) Using the Request object without any extra Headers (or other odata parameters) is apparently not enough to trigger the generation of a new URL.
This does not happen every test. I believe it happens when re-running a test with the same DriveItem in a short time-window. Again, I'm not sure if the JWT token is single-use or time-expired, but if it's expired in any case, I think the service should automatically generate a new one. If that's not practical, just understanding how to explicitly ask for a new one is certainly effective too!
Continuing to debug and try different things, I believe I have found the answer to my question...
Sending a known-false ETag in the request for the DriveItem seems to force the service to send me a new copy. Example code as follows:
//we need a "recent" copy of this object, because the downloadURL is only good for a limited time...
IList<HeaderOption> opts = new List<HeaderOption>();
opts.Add(new HeaderOption("Cache-Control", "no-cache, no-store"));
opts.Add(new HeaderOption("if-none-match", "xyz")); //never match
DriveItem item = await client.Me.Drive.Items[Id].Request(opts).GetAsync();
if (item == null)
{
log.Warn("Could not fetch existing driveItem? " + Id);
return null;
}
object downloadUrl = null;
item.AdditionalData?.TryGetValue(#"#microsoft.graph.downloadUrl", out downloadUrl);
I am still testing this, but initial tests show it to work. I will update this answer when my testing is reasonably conclusive.
Still "bonus points" for anyone who can identify the specific expiration of these URLs (time, number of uses, etc.). Then we can actually check locally whether our object is "stale" and only re-fetch when necessary.

Take all data from Zapier Storage

I need to get all the data from StoreClient (Javascript). The format of the data on the below picture, they are in Zapier Storage.
const store = StoreClient('mysecret');
const value = await store.getMany('mykey'); // or store.get('mykey')
return {result: value}
This code works well. But I need to take and process all stored keys in a loop along with all their child value. I did not find a way :(
I tried store.list_pop(key), but the lists have a different storage format. And the data is not retrieved.
I would recommend using Zapier's storage API which will allow you to retrieve all stored data through a GET request to https://store.zapier.com/api/records. I often have to do the same thing and this works for me.
Have a look at their documentation here. I typically code in Python using the requests library. But I'm sure you could achieve similar results using an ajax or fetch request in Javascript.
EDIT
If I am understanding your question correctly you are trying to 'GET' all of your data stored in Zapier's storage client. As per their API documentation:
Zapier stores your data as a dictionary object which can hold key value pairs. Those values can also be nested dictionaries or lists. Regardless of how you store the data (simple key value pairs, nested lists, nested dictionaries, or some combination of the preceding) a 'GET' request will return the entire object. As stated before I typically use Python's request library to handle HTTP requests but I was able to achieve the same result using a Javascript fetch request. I setup a dummy storage account at https://store.zapier.com/api/records?secret=dog to test and illustrate how this works. See my code below.
var url = "https://store.zapier.com/api/records?secret=dog";
const res = await fetch(url);
const body = await res.json()
return {JSON : body}
Unfortunately, due to my lack of familiarity with Javascript I had to bake the secret into the url, which I don't think is ideal, but for the purposes of this example it does the job. See my output below.
As you can see the 'GET' request returned all data stored in my Zapier storage account. I simply returned the data I retrieved from the 'GET' request but you could of course loop through the results and execute logic as needed. This does not modify any of the data stored, what I often do is pull in all of my stored date with a 'GET' request, modify it, delete the old storage, and 'POST' my modified storage information. This allows me to limit my requests to two calls rather than modifying each individual value.

Using RSA in reverse to decrypt a licence code: encrypt with private key, decrypt with public key

I want to encrypt some values pertaining to a licence code with a secret private key, and then when it's entered in the user's app install it will be decrypted with the public key (stored with the app) to view the encoded data and ensure it was only created by me.
The trouble is it seems that you encrypt with the public key and decrypt with the private key, which is the reverse of what I want.
It's also worth mentioning that the library I'm using called SwiftyRSA only supports encrypting with the public key, and doesn't like it when I use the private key instead. I believe this is because it's being saved to the keychain with kSecAttrKeyClassPublic, because that's what it's expecting, and that causes things to fail.
I have read that the keys are technically interchangeable, but it seems I can't get it to work in my instance. Is this because they public key has a smaller exponent? Is there a way to get the public key to be as "long" as the private key using ssh-keygen, and therefore be able to swap them around? If not, how could I proceed?
The keys aren't always interchangeable (e.g. RSA private keys with CRT parameters) and it is pretty likely that the encryption procedure doesn't protect the key against side channel attacks. You should not use private keys to encrypt, period.
You could use signatures with message recovery if you're really careful.
Otherwise - if you've enough space - you could of course always sign-then-encrypt your license. For this to work (without additional AES encryption) your encryption key pair would have to be quite a bit larger than your signing key though.

IOS/Objective-C/JSON:Obtain single value from Web Service in JSON

I want to obtain a single value from a web service in JSON, just a file name i.e. "picture.png"; based on some parameters passed.
Can IOS (I guess NSJSONSerialization JSONObjectWithData:) handle this single value in JSON or on the server side should I have it send a dictionary key as in {"pic": "picture.gif"}
If there is no picture, I am returning "nopic" so again should I have it return "error" or {"error": "nopic"}
I gather the various JSON specifications are conflicting on this point so my interest is just practical...how best to handle this case.
Thanks for any guidance on this

WinAPI -> CryptoAPI -> RSA, encrypt with private, decrypt with public

Good day.
I need to teach Windows CryptoAPI to encrypt the message with private (not public) part of the key, and decrypt with public. This is necessary to give users information, that they can read, but can't change.
How it works now:
I get the context
CryptAcquireContext(#Prov, PAnsiChar(containerName), nil, PROV_RSA_FULL, 0)
generate a key pair
CryptGenKey(Prov, CALG_RSA_KEYX, CRYPT_EXPORTABLE, #key)
Encrypt (and the problem is here. "key" - a keypair, and the function uses its public part);
CryptEncrypt(key, 0, true, 0, #res[1], #strLen, buffSize)
Decrypt (the same problem here, it uses the private part of the key)
CryptDecrypt(key, 0, true, 0, #res[1], #buffSize)
Thank you for your attention / help.
Update
Yes, I could use a digital signature and other metods...
The problem is that I need to encrypt one database field and make sure that no one but me can change it. It will be possible to read this field only with the help of my program (till someone decompiles it and get public key). This could be done with symmetrical key and digital signatures, but then i will need to create another field and store another key and so on...
I do hope that we can somehow teach WIN API to do as I want. I know that i can do so with RSA, and I hope that somehow WinAPI supports this feature.
Strictly speaking, when "signing" a message:
the person with the private key decrypts the hash with their private key.
they then send that "decrypted" hash along with the message.
the receiver then encrypts the signature with the public key
If the "encrypted" hash matches the hash of the original message, you know the message has not been altered, and was sent by the person with the private key. The following pseudo-code represents the signing algorithm:
//Person with private key generating message and signature
originalHash = GenerateHashOfMessage(message);
signature = RsaDecrypt(originalHash, privateKey);
//Receiver validating signed message
hash = GenerateHashOfMessage(message);
originalHash = RsaEncrypt(signature, publicKey);
messageValid = (hash == originalHash);
This same mechanism can be used to accomplish what you want. Except you don't care about hashes, you just want to encrypt some (small) amount of data:
//Person with private key
cipherText = RsaDecrypt(plainText, privateKey);
//Person with public key
plainText = RsaEncrypt(cipherText, publicKey);
i'll leave the CryptoAPI calls as an excercise - since i'm still trying to figure out Microsoft's Crypto API.
Encrypting data with the private key and decrypting it with the public key isn't supported because anyone with the "published" public key could decrypt it. What's the value in encrypting it then?
If you want to verify that data hasn't been changed, you will want to sign the data instead. Signing encrypts a hash of the data with the private key. Look at the signing functions.
You may be able to trick out the signing functions to do what you want. I've done this with other implementations, but I haven't tried with the Microsoft CryptoAPI.
Also, note that with RSA encryption, the plain text message cannot be longer than the key. So, if you are using a 2048 bit key, you can only encrypt a message body of up to 256 bytes (minus a few for overhead).
Consider using asymmetric encryption just to pass a symmetric key, and use the symmetric key to encrypt and decrypt any size data.
Update
You may be able to use the CryptSignHash() function for this. Normally, this is used to "sign" a hash, but you can put any data you want into the hash:
Set the hash value in the hash object by using the HP_HASHVAL value of
the dwParam parameter in CryptSetHashParam.
You might be limited to so many bytes if the input is expected to be a SHA1 hash value.
Alternatively, you may wish to consider using OpenSSL. If I recall correctly, it's pretty straight forward to use its RSA signing functions to encrypt with the private key.
Also, I accomplished the same thing using the old (freeware) version of SecureBlackbox. You may be able to find the old free version, but it's not Unicode friendly, so you'll have some conversion to do if you're using a new Delphi. I've done this in the past also, so it's not too difficult.
You may also consider trying out the current SecureBlackbox and purchase it if it works for you.
Otherwise, as you stated, sign it to detect tampering, and encrypt it with a symmetric key that only the program knows in order to obfuscate it.
If they crack your code, anything's fair game anyway.

Resources