Import phantom wallet private key into solana CLI - solana

I need to use a Phantom Wallet through the Solana CLI, but I'm unable to configure it.
For example, to check balance using
solana balance --keypair fileexportedfromphantom
but can't read the info.
How do I convert that private key into a valid form for use in Solana CLI?

Try:
solana-keygen recover 'prompt://?key=0/0' -o <file.json>
And enter the 24-word recovery phrase from Phantom under "Show Secret Recovery Phrase".
This is because Phantom uses the 0/0 derivation path for wallets and needs the extra provided path to get to the correct account.
You can use the same command with 1/0, 2/0 ... N/0 to get the different Phantom derived accounts.
See here for more info about hierarchical derivation with the Solana tools: https://docs.solana.com/wallet-guide/paper-wallet#hierarchical-derivation
Or use the Solflare wallet to check the derivation paths for your particular 24 word phrase here: https://solflare.com/access
As per the recent comment from #FutForFut, this assumes you have or want to use the Secret Recovery Phrase from Phantom. In certain cases, you might only have the private key from Phantom ("Show Private Key") in menus. This is a base58 encoded key, and you'll need to convert that into a byte-array in a JSON file.
Here's the Javascript snippet, using the bs58 package (https://www.npmjs.com/package/bs58):
const bs58 = require('bs58');
const fs = require('fs');
b = bs58.decode('privatekeyexportedfromphantom');
j = new Uint8Array(b.buffer, b.byteOffset, b.byteLength / Uint8Array.BYTES_PER_ELEMENT);
fs.writeFileSync('key.json', `[${j}]`);
Update fields privatekeyexportedfromphantom and key.json as required.

It's a bit annoying, but you'll have to decode the base-58 private key returned by Phantom into an array of bytes. Here's a simple Python code snippet to accomplish this, using the base58 package (https://pypi.org/project/base58/):
import base58
byte_array = base58.b58decode(MY_PRIVATE_KEY_IN_BASE58)
json_string = "[" + ",".join(map(lambda b: str(b), byte_array)) + "]"
print(json_string)
You can pipe that output to a file, and then use that as your --keypair with the CLI tools.

Related

How to use S3 SSE C (Server Side Encryption with Client Provided Keys) with Ruby

I'm trying to upload a file to S3 and have it encrypted using the SSE-C encryption options. I can upload without the SSE-C options, but when I supply the sse_customer_key options I'm getting the following error:
ArgumentError: header x-amz-server-side-encryption-customer-key has field value "QkExM0JGRTNDMUUyRDRCQzA5NjAwNEQ2MjRBNkExMDYwQzBGQjcxODJDMjM0\nnMUE2MTNENDRCOTcxRjA2Qzk1Mg=", this cannot include CR/LF
I'm not sure if the problem is with the key I'm generating or with the encoding. I've played around with different options here, but the AWS documentation is not very clear. In the general SSE-C documentation it says you need to supply a x-amz-server-side​-encryption​-customer-key header, which is described as this:
Use this header to provide the 256-bit, base64-encoded encryption key
for Amazon S3 to use to encrypt or decrypt your data.
However, if I look at the Ruby SDK documentation for uploading a file the 3 options have a slightly different description
:sse_customer_algorithm (String) — Specifies the algorithm to use to when encrypting the object (e.g.,
:sse_customer_key (String) — Specifies the customer-provided encryption key for Amazon S3 to use in
:sse_customer_key_md5 (String) — Specifies the 128-bit MD5 digest of the encryption key according to RFC
(I didn't copy that wrong, the AWS documentation is literally half-written like that)
So the SDK documentation makes it seem like you supply the raw sse_customer_key and that it would base64-encode it on your behalf (which makes sense to me).
So right now I'm building the options like this:
sse_customer_algorithm: :AES256,
sse_customer_key: sse_customer_key,
sse_customer_key_md5: Digest::MD5.hexdigest(sse_customer_key)
I previously tried doing Base64.encode64(sse_customer_key) but that gave me a different error:
Aws::S3::Errors::InvalidArgument: The secret key was invalid for the
specified algorithm
I'm not sure if I'm generating the key incorrectly or if I'm supplying the key incorrectly (or if it's a different problem altogether).
This is how I'm generating the key:
require "openssl"
OpenSSL::Cipher.new("AES-256-CBC").random_key
Oh, did you notice that your key contains '\n'? That's most probably why you get the CR/LF error:
QkExM0JGRTNDMUUyRDRCQzA5NjAwNEQ2MjRBNkExMDYwQzBGQjcxODJDMjM0(\n)nMUE2MTNENDRCOTcxRjA2Qzk1Mg=
As mentioned by the colleague in the comments, strict_encode64 is an option, as it complies to RFC 2045.
By the way, I got this insight from here: https://bugs.ruby-lang.org/issues/14664
Hope it helps! :)
First of all, please make sure that you are using the latest version of the SDK (2.2.2.2) from here
So, As I understand while we generate the presigned URL, we have to specify the SSECustomerMethod and when consuming the URL, the "x-amz-server-side-encryption-customer-key" header is set with the customer key, you also need to set the "x-amz-server-side-encryption-customer-algorithm" header.
var getPresignedUrlRequest = new GetPreSignedUrlRequest
{
BucketName = bucketName,
Key = "EncryptedObject",
SSECustomerMethod= SSECustomerMethod.AES256,
Expires = DateTime.Now.AddMinutes(5)
};
var url = AWSClients.S3.GetPreSignedURL(getPresignedUrlRequest);
var webRequest = HttpWebRequest.Create(url);
webRequest.Headers.Add("x-amz-server-side-encryption-customer-algorithm", "AES256");
webRequest.Headers.Add("x-amz-server-side-encryption-customer-key", base64Key);
using (var response = webRequest.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
var contents = reader.ReadToEnd();
}

Google Server to Server OAuth Error

I'm trying to connect my server to Google's API but I keep getting the following error.
google.auth.exceptions.RefreshError: ('invalid_scope: h is not a valid audience string.', u'{\n "error" : "invalid_scope",\n "error_description" : "h is not a valid audience string."\n}')
I've looked around but I just can't seem to get why google's supplied code is giving me that error. I think it's a problem with my service.json, but I can't pinpoint what it is.
This is the code, which is pretty much swiped from Google with very limited changes.
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
SERVICE_ACCOUNT_FILE = 'service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive = googleapiclient.discovery.build('drive', 'v3', credentials=credentials)
response = drive.files().list(
pageSize=10,fields="nextPageToken, files(id, name)").execute()
print(response)
What I'm looking to do is automatically download a spreadsheet to local using Google's API maybe once an hour without user verification.
I'm having this error.
It looks like scopes is expected to be iterable, so when a single string is given, the library processes each letter separately (the first being 'h').
Try changing line 4 to add brackets:
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']

Check if a private key is available from an agent using Ruby's Net::SSH

I'm using Net::SSH to automate access to remove hosts from a ruby program, using key authentication. The program does not dictate where the user should put the private key, instead relying on the user's SSH agent to provide the required keys (as it should).
The problem is if the required private key is not available, the connection will fail - and this may happen a long way into the program (the SSH connection is one of the last things we do after doing a lot of other - not easily reversible - operations).
Supposed that I know what private key the user should have (as specified by the key fingerprint), how can I do this check from ruby - other then execute ssh-add -l and grepping the output?
I've looked at Net::SSH KeyFactory class, but it only lets you load private keys if you know the name of the file in which they are stored.
I figured it out - Net::SSH::Authentication::KeyManager has what I need:
hasidentity = false
Net::SSH::Authentication::KeyManager.new(nil?).each_identity do |i|
hasidentity |= i.fingerprint == 'my:ke:ys:fi:ng:er:pr:in:t'
end
KeyManager also has a collection called identities, though from what I understand, that holds only keys loaded directly into Net::SSH, while each_identity iterates over all available identities, including those available from an agent.

CryptExportKey: how to export private key from PKCS#12 store?

I need to export public and private RSA key from certificate, stored in PKCS#12 format, on Windows.
I can open certificate store with CertOpenStore(), then find certificate with CertFindCertificateInStore() and acquire private key with CryptAcquireCertificatePrivateKey().
It works Ok. Then I extract user key with CryptGetUserKey() It works too.
But CryptExportKey() with blob type PRIVATEKEYBLOB fails.
CryptSetKeyParam() with KP_PERMISSIONS and set permission CRYPT_EXPORT also fails.
How could I get all RSA key pair parameters in such case?
All examples use CryptGenKey() to create and THEN export key, but I need to export existing key pair to simple binary form.
Found solution: if use more specific PFXImportCertStore() to open PKCS#12 file instead of generic CertOpenStore() with CERT_STORE_PROV_PKCS12 store provider, it accepts flag CRYPT_EXPORTABLE and key could be exported with CryptExportKey().

How can I asymmetrically encrypt data using OpenPGP with Ruby?

This feels like it should be dead simple, yet I'm not having any luck.
The scenario is this: I have a public *.asc key file. I want to use this file (not my personal keyring) to encrypt data on a server, so that I can decrypt it locally with a secret key.
From the command line I can achieve this using gpg, but I'd prefer to use a Ruby library that isn't just a wrapper around the CLI (i.e., presumably one that provides bindings to the C library). I've looked at the GPGME and OpenPGP gems and haven't been able to figure out how to use them. The documentation (especially for OpenPGP) is quite sparse.
Here, for example, is something I've tried using GPGME, without any luck:
key = GPGME::Data.new(File.open(path_to_file))
data = GPGME::Data.new("I want to encrypt this string.")
# Raises GPGME::Error::InvalidValue
GPGME::Ctx.new do |ctx|
e = ctx.encrypt(key, data)
end
Has anyone been through this already? Surely this can't be that complicated?
I believe I've now got this figured out. It was actually just a few simple pieces I was missing:
Initializing the GPGME::Ctx object with a keylist_mode of GPGME::KEYLIST_MODE_EXTERN.
Importing the public key file using GPGME::Ctx#import.
Using GPGME::Crypto#encrypt to perform the encryption and specifying the correct recipient.
So my solution now looks like this:
key = GPGME::Data.new(File.open(path_to_file))
data = GPGME::Data.new("I want to encrypt this string.")
GPGME::Ctx.new(GPGME::KEYLIST_MODE_EXTERN) do |ctx|
ctx.import(key)
crypto = GPGME::Crypto.new(:armor => true, :always_trust => true)
e = crypto.encrypt(data, :recipients => "recipient#domain.com")
end

Resources