Android KeyStore Notes

Create PrivateKey/PublicCertificate Pair

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void createNewKeys(View view) {
String alias = aliasText.getText().toString();
try {
// Create new key if needed
if (!keyStore.containsAlias(alias)) {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(alias)
.setSubject(new X500Principal("CN=Sample Name, O=Android Authority"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
}
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
refreshKeys();
}

Import PrivateKey/PublicCertificate Pair

The private key cannot be encrypted.
The password parameter of setKeyEntry has to be null.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// The key/certificate are the content between BEGIN and END in pem format
final private String PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCadLCqO4yNjdpZz26sTPXLx6JcgtNibHHldL//xRwZyYqX6udIbOH6Poau/niWEGeupBjN5qnCeDWTjNDBHGm+H+Se62V7PVH93O8bPRRoDzg4xZWrPhbDIZ6DlSvPh9/JakegNl4Nx7L9GVFbXYmFyqv6gziFjEbIGRBz9vW2QdbjxnmhnkiMobzI0Pxx/GMt1QZ92ezlsXUerECejVFStfr8SDlfZvKljIoVOJfZBBdTPh9zEi455dka+bPRv6w1v2SppNppC1jCargNcZ1dLr9ERKEh6hYdNP+qnRTeFZTAxIxiocRy0jvpvNs7bVP1PogOnK0ggl0khU9bontdAgMBAAECggEAUcVFYlp0ZtyapMF0zjNQTbo68s8wKgNPqTLOExK/dceFYDg0idtbJ6jClRKTtJ6qxYKKvzdG2HXbp2n9er8YHFe2KYxmBYDJT6UP0VPc4dps4WF5g1czpcq+qNrofs5oY7GoieE+mf0HfYdR0xUKIZLSyaV+3vUM5BKg60Prgbk3BcC79wDt/WlNT23vZrLop3KuW611v8DSMA73nHclWSh9kVcEcgctc3idprFfAjlF1pWybIHSgkOBd8XIJ94SBsMKqGKF5MRv2doRttUHz2kCw+MvdLRXm7ry/CzAqEwYL/KUMUrnzVN5JNllyB/Z/nZSIu8C0vsmPMWfCRIb4QKBgQDIChs4vKORSU8f2QXphTufD0EdtJJsM37AjJxhBM4EKQBreE0Ci0LBXlbdrodTE5JsjvNyL8S5jNOt79xwLq8/cpaBRXPoRkCNKckPQMlFWF4bFUjRAXSTuc0daF/4zqH8AJu4nLiBDm+ytrQlHDi/f6lLUO/2DgfT/rbx7gEg3wKBgQDFqhhSmr8P0NDK6c6+AoRTxhJcfcFxIi7Llad1CBPuxsvDn3Q8XpeI+QNfygrFPxi2g6GOnJQ8guGe9IUX2zY/RqJqEM6Pgc7zv0etCvC4jd6dW/ox0Td/ymOVltOIofsAQQ3SRNNqSgjin3KlOpyCw38J6NCevQXFeU0CPcA/QwKBgHGYS50MglYeqzAKrbDOV+0bXH7h68RF+dSeBK+Tauox3mspBZJMQrxMNkfstCwZES1UgCp3td8oeYxsiWGrIRmGmLEQH6HnQwDmmaZvw9v9MnNuwsrtaKX6/N+WRemkbZgNQGC1npCrAgMafXIVdKRKeniqnZm8nfVkz77SyRFBAoGBALr/H+OF4hrkQaK1bpDzcJyQVe6KSebtn7eZ7MIa0kCicUKwJxa1pkY+zaJhUa8o8gg4ny57kwFsEGaAjSj0iW1zNVOCcufwtgiCfRyHrRProx7bVOasNwT+QxfRiG1KUFr9MEYsNpXnVGCQ17TYrhhHOnf1eOezizI2f1QPd0BhAoGBAIDTegY9P1e1fzPALn9puHElapUXlXwZfiT9J1C6GkYywYwrXDkYXKXb+mvNIbL8YxKZ0ONecVxcmd693yh33VSGIngOvmGNhRmkY8EpTc2MsZXtu3Yej1Nn/q3y7X0+XWJ5YI3A1dCILjdfXAIlwb6wDIyxich8sgBEiEJotI1Y";
final private String UNSIGNED_CERT = "MIID7TCCAtWgAwIBAgIJAKvJ99aAhppSMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxETAPBgNVBAoMCFNlbGZ0ZXN0MRQwEgYDVQQLDAtTZWN0aW9uU2VsZjERMA8GA1UEAwwIdGVzdC5uZXQxHDAaBgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5uZXQwHhcNMTcwNDA0MDE1NTEyWhcNMTcwNTA0MDE1NTEyWjCBjDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MREwDwYDVQQKDAhTZWxmdGVzdDEUMBIGA1UECwwLU2VjdGlvblNlbGYxETAPBgNVBAMMCHRlc3QubmV0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmnSwqjuMjY3aWc9urEz1y8eiXILTYmxx5XS//8UcGcmKl+rnSGzh+j6Grv54lhBnrqQYzeapwng1k4zQwRxpvh/knutlez1R/dzvGz0UaA84OMWVqz4WwyGeg5Urz4ffyWpHoDZeDcey/RlRW12Jhcqr+oM4hYxGyBkQc/b1tkHW48Z5oZ5IjKG8yND8cfxjLdUGfdns5bF1HqxAno1RUrX6/Eg5X2bypYyKFTiX2QQXUz4fcxIuOeXZGvmz0b+sNb9kqaTaaQtYwmq4DXGdXS6/REShIeoWHTT/qp0U3hWUwMSMYqHEctI76bzbO21T9T6IDpytIIJdJIVPW6J7XQIDAQABo1AwTjAdBgNVHQ4EFgQUgQkNHWSC8zCUG5VvNK6+V0saxDYwHwYDVR0jBBgwFoAUgQkNHWSC8zCUG5VvNK6+V0saxDYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEHLEHBjmGbmE3CFtfStEHcvG1LIG8B96gBHKBY28XbdGQoxlZWlIfdsCjB80XP7S0Ku701N/Keh0kjDcEHp/TbOERwy4Icq/RdDnEj6Lbbc1I/c5w4mRu4KZPOpmdfeOPFBb2iFCpXw8iHUPCTnyQhkkL+kSy2bKxnrwj+MeRBudRhjdSWi3ZUKvxmC2LW4pMua9Y9MWANpl6/h9wLGRcicAmwZoUnHvLno9ccNc5DVq1Cbb73rpG1aMXoRdrcJqHmXMKC9g1cAKSuPfHgLASKKfVoLszv661r2yOI4MmiZKQhUHkbvt54F80P/t8AXpUTLDQ5btiQiUSF+IeoUQPg==";
final private String SIGNED_CERT = "MIID+zCCAuOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEUMBIGA1UECgwLU2Ftc3VuZ1Rlc3QxFDASBgNVBAsMC1NlY3Rpb25UZXN0MREwDwYDVQQDDAh0ZXN0Lm9yZzEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0Lm9yZzAeFw0xNzA0MDQwMjAwNDRaFw0xODA0MDQwMjAwNDRaMHQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UECgwGU2VsZkNBMRYwFAYDVQQLDA1TZWN0aW9uU2VsZkNBMREwDwYDVQQDDAh0ZXN0Lm5ldDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJp0sKo7jI2N2lnPbqxM9cvHolyC02JsceV0v//FHBnJipfq50hs4fo+hq7+eJYQZ66kGM3mqcJ4NZOM0MEcab4f5J7rZXs9Uf3c7xs9FGgPODjFlas+FsMhnoOVK8+H38lqR6A2Xg3Hsv0ZUVtdiYXKq/qDOIWMRsgZEHP29bZB1uPGeaGeSIyhvMjQ/HH8Yy3VBn3Z7OWxdR6sQJ6NUVK1+vxIOV9m8qWMihU4l9kEF1M+H3MSLjnl2Rr5s9G/rDW/ZKmk2mkLWMJquA1xnV0uv0REoSHqFh00/6qdFN4VlMDEjGKhxHLSO+m82zttU/U+iA6crSCCXSSFT1uie10CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFIEJDR1kgvMwlBuVbzSuvldLGsQ2MB8GA1UdIwQYMBaAFODmZfUgqfPNVJEhF0ekF9Qh6La2MA0GCSqGSIb3DQEBCwUAA4IBAQBGnlZqIhC9l3wWYlO8AJ4toLbQnymkoknzOfMLCRCCHLtp0y23twb/Qp5D0D1bHb7VOKByqeiLCu3CFb8/nHAElqbcoFkmEvFv5QdxKefzRDCgj8KyR+teyJjekXHuaqZSPL1nETlvP+mRkEP4QGb1mvdmjZs3cMcIFJxD6MygEhIeJeUu2VyPAriVvt5Wk/4PEdJ6/ft5zSZyiCCI6nPyrPjixonDqnCmapbiYYqhGCRgaF02f3nQ61/T9KiZO8+nrh0tIKpjKz3A+qQgnF0kSjSW1MGZnHw2zxzk3AjSPCvXUvoCJKBj5Wgd1TFHzJaegaBDW9OSmJPiZgMZgyNO";

public void installPrivateKeyPair(View view) {
try{
PrivateKey privateKey = null;
Certificate[]chain = {null};
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(PRIVATE_KEY, Base64.DEFAULT)));

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
chain[0] = certFactory.generateCertificate(new ByteArrayInputStream(Base64.decode(UNSIGNED_CERT, Base64.DEFAULT)));
keyStore.setKeyEntry("testAlias", privateKey, null, chain);
refreshKeys();
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}

// overwrite the unsigned certificate with the signed one, the private key remains the same
public void installSignedCert(View view) {
try{
PrivateKey privateKey = null;
Certificate[]chain = {null};
privateKey = (PrivateKey) keyStore.getKey("testAlias", null);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
chain[0] = certFactory.generateCertificate(new ByteArrayInputStream(Base64.decode(SIGNED_CERT, Base64.DEFAULT)));

keyStore.setKeyEntry("testAlias", privateKey, null, chain);
refreshKeys();
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}

Encrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void encryptString(String alias) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

String initialText = startText.getText().toString();
if(initialText.isEmpty()) {
Toast.makeText(this, "Enter text in the 'Initial Text' widget", Toast.LENGTH_LONG).show();
return;
}

Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, inCipher);
cipherOutputStream.write(initialText.getBytes("UTF-8"));
cipherOutputStream.close();

byte [] vals = outputStream.toByteArray();
encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT));
} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}

Decrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void decryptString(String alias) {
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
PrivateKey privateKey = privateKeyEntry.getPrivateKey();

Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
output.init(Cipher.DECRYPT_MODE, privateKey);

String cipherText = encryptedText.getText().toString();
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), output);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte)nextByte);
}

byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i).byteValue();
}

String finalText = new String(bytes, 0, bytes.length, "UTF-8");
decryptedText.setText(finalText);

} catch (Exception e) {
Toast.makeText(this, "Exception " + e.getMessage() + " occured", Toast.LENGTH_LONG).show();
Log.e(TAG, Log.getStackTraceString(e));
}
}

Reference

Simple Android app showing how to use the Android Keystore to create, retrieve and delete Public/Private keypairs

Domain Names are Not Protected by HTTPS

Domain names (e.g. drive.google.com) are not protected/encrypted by HTTPS because of Server Name Indication (SNI).
SNI is an extension to the TLS protocol by which a client indicates which hostname it is attempting to connect to at the start of the handshaking process. This allows a server to present multiple certificates on the same IP address and TCP port number and hence allows multiple secure (HTTPS) websites (or any other Service over TLS) to be served off the same IP address without requiring all those sites to use the same certificate. The desired hostname is not encrypted, so an eavesdropper can see which site is being requested.

Reference:
Server Name Indication
The First Few Milliseconds of an HTTPS Connection

How to Get Rid of the Black Screen Issue with NoMachine Virtual Desktop

When proprietary drivers for AMD and NVIDIA video cards are installed on the server host, users get a black screen when running virtual desktops. This doesn’t occur when using Open Source drivers like Radeon or nouveau.

In order to set LD_LIBRARY_PATH for NoMachine sessions, specify path to the Mesa 3D graphics library in the node configuration, the /usr/NX/etc/node.cfg file.

To do that:

  1. Edit the /usr/NX/etc/node.cfg file.

  2. Uncomment the DesktopCommandLibraryPath key.

  3. Set the proper path to Mesa library in the DesktopCommandLibraryPath key.

For example on Ubuntu 14.04 64 bit:

DesktopCommandLibraryPath “/usr/lib/x86_64-linux-gnu/mesa”

and on Ubuntu 14.04 32 bit:

DesktopCommandLibraryPath “/usr/lib/i386-linux-gnu/mesa/“

Path to be set in the DesktopCommandLibraryPath key must point to the directory containing the libGL.so* libraries.

Reference:

https://www.nomachine.com/AR09L00814

Android Keystore System Notes

Similar to KDEWallet

Security Features

  • Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable. (extraction prevention)
  • Moreover, it offers facilities to restrict when and how keys can be used, such as requiring user authentication for key use or restricting keys to be used only in certain cryptographic modes. (Key Use Authorizations)

Extraction Prevention

The Keystore system is used by the KeyChain API as well as the Android Keystore provider feature.
Key material never enters the application process.
Key material may be bound to the secure hardware.

Key Use Authorizations

Android Keystore lets apps specify authorized uses of their keys when generating or importing the keys. Once a key is generated or imported, its authorizations can not be changed.

Supported key use authorizations:

  • cryptography: authorized key algorithm, operations or purposes (encrypt, decrypt, sign, verify), padding schemes, block modes, digests with which the key can be used;
  • temporal validity interval: interval of time during which the key is authorized for use;
  • user authentication: the key can only be used if the user has been authenticated recently enough.

Keychain vs Keystore Provider

KeyChain: system-wide credentials, need users to choose which credential an app can access, allows several apps to use the same set of credentials with user consent.
Keystore provider: let an individual app store its own credentials that only the app itself can access, requires no user interaction to select the credentials.

Reference

Android Keystore System

Manage Hexo Blog with Git

Just init the git repo and add *.
Hexo has already written the .gitignore to exlude the files you should not commit.
If there are .git inside theme, you shoud delete the .git folder or ignore it.

1
2
3
git init
git add *
git commit

Regex Notes

Content

(?s) For “single line mode” makes the dot match all characters, including line breaks. Not supported by Ruby or JavaScript.
*? Ungreedy
(?<=(regex)) Positive Lookbehind
(?<!(regex)) Negative Lookbehind
(?=(regex)) Positive Lookahead
(?!(regex)) Negative Lookahead

Reference:

Regular-Expressions.info Tutorial

Markdown Notes

Content:

Setext-style headers for h1 and h2 are created by “underlining” with equal signs (=) and hyphens (-)
e.g.

1
2
3
4
A First Level Header
====================
A Second Level Header
---------------------

Unordered List */+/-

Inline Code

1
`<code>`

Code Block: indent every line of the block by 4 spaces or 1 tab

1
2
3
<blockquote>
<p>For example.</p>
</blockquote>

Code Block:

1
2
```<language>
code content

## Reference:
[Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)
[MARKDOWN SYNTAX & GITHUB FLAVORED MARKDOWN](https://enterprise.github.com/downloads/en/markdown-cheatsheet.pdf)

Trusty OS

Trusted applications and services

Trusted applications run as isolated single-threaded processes under the Trusty OS kernel. Each process runs in its own virtual memory sandbox utilizing the MMU capabilities of the TEE processor. The kernel schedules these processes using a priority-based, round-robin scheduler driven by a secure timer tick. In the current version of Trusty, all Trusty applications share the same priority.

Trusted applications are written as event-driven servers waiting for commands from other applications or from applications running on the main processor. Trusted applications can also be clients of other trusted server applications.

Ports and channels

Ports are used by Trusty applications to expose service end-points in the form of a named path to which clients connect. e.g. “com.google.servicename”.
Channels: symmetric, bi-directional connection instances of a port