Related
I have an issue with a SecKeyRef generated on iOS device - when trying to use it on Java server, the exception is thrown:
InvalidKeyException: EC domain parameters must be encoded in the algorithm identifier
here's the code snippet from the server code:
String key = ...
byte[] byteKey = Base64.decode(key.getBytes(StandardCharsets.UTF_8));
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("EC");
return kf.generatePublic(X509publicKey);
The exception is thrown by kf.generatePublic(X509publicKey);
The key is created on iOS, using SecKeyGeneratePair
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeEC forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:256] forKey:(__bridge id)kSecAttrKeySizeInBits];
// Set the private key dictionary
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:self.privateTag forKey:(__bridge id)kSecAttrApplicationTag];
// Set the public key dictionary
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:self.publicTag forKey:(__bridge id)kSecAttrApplicationTag];
// Set attributes to top level dictionary
[keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
// Generate key pair
OSStatus sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKeyRef, &privateKeyRef);
The key pair is created successfully. I then extract key's bit data using following code
CFDataRef publicKeyBitsRef = NULL;
NSMutableDictionary *queryPublicKey = [NSMutableDictionary dictionary];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:self.publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeEC forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnData];
// Get the key bits.
OSStatus sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyBitsRef);
Then, I export the key using CryptoExportImportManager
NSData *publicKeyIDERData = [manager exportPublicKeyToDER:keyBits keyType:(__bridge NSString*)kSecAttrKeyTypeEC keySize:256];
NSString *derKeyString = [publicKeyIDERData base64EncodedStringWithOptions:0];
According to this answer, the DER header contains info about key type and parameters and for secp256r1 key it's equivalent of following data
[
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00
]
Which is indeed added to key header on export.
derKeyString is then sent to backend and processed using Java code mentioned above. However, the exception is thrown.
The same backend processes also the key created on Android device using following code
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(
new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(true).build());
keyPairGenerator.generateKeyPair();
The Android key works just fine.
What am I doing wrong? Have I forgotten about something while creating keys with SecKeyGeneratePair or exporting the public key?
I solved the problem, although I'm not sure why.
What I did is I ditched CryptoExportImportManager library and I'm manually creating key data, like so:
unsigned char _encodedECOID[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00
};
NSMutableData *data = [NSMutableData new];
[data appendBytes:_encodedECOID length:sizeof(_encodedECOID)];
[data appendData:keyBits]; // keyBits is od NSData type
Now the Java server properly creates public key from my string (base64 encoded from data).
However, having looked at source code of CryptoExportImportManager, the way it creates the encoded string from my key bits looks like that (in Swift):
let curveOIDHeader: [UInt8] = [0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00]
let curveOIDHeaderLen: Int = 26
var data = Data(bytes: curveOIDHeader, count: curveOIDHeaderLen)
data.append(rawPublicKeyBytes)
It basically does exactly the same thing. So where's the difference?
Now the only thing that comes to mind is the difference in how the header is stored - in my case it's an array of unsigned char, in library's case it's an array of UInt8.
According to this answer, C types unsigned char and uint8_t are not equivalent, they are only guaranteed to have the same length, but can differ in i.e. byte ordering.
Though that question had nothing to do with Swift's UInt8 (but was tagged C, of which Objective-C is superset), the documentation of Swift's UInt8 type says nothing about it's relation to unsigned char type, that would be the only reasonable explanation I can see.
I have a java program where a read a identitynumber. Like "1234567" Now i want to convert that ascii value to a hexadecimal value and put that in a hexadecimal byte array like this :
byte[] bytes = {0x02, 0x0b, 0x39, 0x36, 0x31, 0x31, 0x32, 0x36, 0x31, 0x39, 0x39, 0x34, 0x37, 0x32, 0x03};
Problem is .. I have no idea how that i can do that .. Have you a solution or tips ? Thanks !
String foo = receivedData.substring(10,21);
BigInteger data = new BigInteger(foo);
I am unit testing a netty pipeline using the frame based decoder. It looks like the framing is incorrect if I use buffer size that is smaller that the largest frame. I am testing with a file that contains two messages. The length field is the second work and includes the length of the entire message including the length field and the work before it.
new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0)
I am reading a file with various block sizes. The size of the first message is 348 bytes, the second is 456 bytes. If block size of 512, 3456, or larger, is used both messages are read and correctly framed to the next handler which for diagnostic purposes will print out as a hexadecimal string the contents of the buffer it received. If a smaller block size is used framing errors occur. The code used to read and write the file is shown below.
public class NCCTBinAToCSV {
private static String inputFileName = "/tmp/combined.bin";
private static final int BLOCKSIZE = 456;
public static void main(String[] args) throws Exception {
byte[] bytes = new byte[BLOCKSIZE];
EmbeddedChannel channel = new EmbeddedChannel(
new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0),
new NCCTMessageDecoder(),
new StringOutputHandler());
FileInputStream fis = new FileInputStream(new File(inputFileName));
int bytesRead = 0;
while ((bytesRead = fis.read(bytes)) != -1) {
ByteBuf buf = Unpooled.wrappedBuffer(bytes, 0, bytesRead);
channel.writeInbound(buf);
}
channel.flush();
}
}
Output from a successful run with block size of 356 bytes is show below (with the body of the messages truncated for brevity
LOG:DEBUG 2017-04-24 04:19:24,675[main](netty.NCCTMessageDecoder) - com.ticomgeo.mtr.ncct.netty.NCCTMessageDecoder.decode(NCCTMessageDecoder.java:21) ]received 348 bytes
Frame Start========================================
(byte) 0xbb, (byte) 0x55, (byte) 0x05, (byte) 0x16,
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x5c,
(byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
(byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x50, (byte) 0x3a, (byte) 0xc9, (byte) 0x17,
....
Frame End========================================
Frame Start========================================
(byte) 0xbb, (byte) 0x55, (byte) 0x05, (byte) 0x1c,
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xc8,
(byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x02,
(byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x04, (byte) 0x02, (byte) 0x00, (byte) 0x01,
If I change the block size to 256, the wrong bytes seem to be read as the length field.
Exception in thread "main" io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 65536: 4294967040 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)
TL;DR; Your problem is caused because netty reuses the passed in bytebuf, and then you are overwriting the contents.
LengthFieldBasedFrameDecoder is designed through inheritance to reuse the passed in ByteBuf, because it is useless to let the object decay through garbage collection when you can reuse it because its reference count is 1. The problem however comes from the fact that you are changing the internals of the passed in bytebuf, and therefore changing the frame on the fly. Instead of making a wrappedBuffer, that uses your passed in variable as storage, you should use copiedBuffer, because that one properly makes a copy of it, so the internals of LengthFieldBasedFrameDecoder can do freely things with it.
I already have a EC key pair(secp256r1) in a binary format which is stored in a byte array, like this:
// private key, 32 bytes
byte[] privKey = {0x4c, (byte)0xc7, (byte)0xcf, 0x68, (byte)0x91, 0x18, (byte)0x96, (byte)0xc8, (byte)0xe2, (byte)0xf9, (byte)0xc8, (byte)0xcc, 0x2f, 0x7f, 0x0a, (byte)0xa2, 0x1c, 0x6a, (byte)0xcb, (byte)0xba, 0x38, 0x1c, 0x10, (byte)0x9a, (byte)0xfe, (byte)0x91, 0x18, (byte)0xf6, (byte)0xca, (byte)0xd9, 0x0f, 0x0b};
//public key, 65 bytes, which is contained in a X.509 certificate
byte[] pubKey = {0x04, 0x72, (byte)0x9a, 0x71, (byte)0xd0, (byte)0x81, 0x62, 0x42, (byte)0x84, (byte)0x92, (byte)0xf2, (byte)0xd9, 0x61, (byte)0x92, 0x4d, 0x37, 0x44, 0x3a, 0x4f, 0x1b, (byte)0xda, 0x58, 0x0f, (byte)0x8a, (byte)0xea, 0x29, 0x20, (byte)0xd2, (byte)0x99, 0x7c, (byte)0xbe, (byte)0xa4, 0x39, 0x60, (byte)0xce, 0x72, (byte)0x9e, 0x35, (byte)0xc1, (byte)0xf7, 0x40, (byte)0x92, (byte)0xf2, 0x25, 0x0e, 0x60, 0x74, (byte)0x82, 0x3f, (byte)0xc5, 0x7f, 0x33, 0x60, (byte)0xb7, (byte)0xcd, 0x39, 0x69, (byte)0xc3, (byte)0xc3, 0x12, 0x5e, (byte)0xce, 0x26, 0x5c, 0x29};
This EC key pair is generated by openssl. I want to store this EC key pair in my javacard applet, so that I can signature message with this EC private key every time.
But I don't find any appropriate API in javacard 3 to set the EC key pair.
I use this project https://github.com/Yubico/ykneo-curves/blob/master/applet/src/com/yubico/ykneo/curves/SecP256r1.java to set the parameters in secp256r1.
UPDATE
I do have set the parameters setW in ECPublicKey and setS in ECPrivateKey, and other parameters according to https://github.com/Yubico/ykneo-curves/blob/master/applet/src/com/yubico/ykneo/curves/SecP256r1.java. Like this:
privKey.setFieldFP(p, (short) 0, (short) p.length);
privKey.setA(a, (short) 0, (short) a.length);
privKey.setB(b, (short) 0, (short) b.length);
privKey.setG(G, (short) 0, (short) G.length);
privKey.setR(r, (short) 0, (short) r.length);
byte[] privData = {(byte)0x25, (byte)0xc9, (byte)0xec, (byte)0xdc, (byte)0x4c, (byte)0x59, (byte)0xa3, (byte)0xe0, (byte)0x4f, (byte)0x01, (byte)0x56, (byte)0x97, (byte)0xf3, (byte)0xcb, (byte)0x60, (byte)0x5b, (byte)0x84, (byte)0x49, (byte)0x45, (byte)0x3a, (byte)0xe2, (byte)0x0e, (byte)0xd1, (byte)0xbd, (byte)0xc0, (byte)0xa7, (byte)0xe1, (byte)0xfa, (byte)0x82, (byte)0xee, (byte)0x3c, (byte)0x73};
privKey.setS(privData, (short) 0, (short) privData.length);
pubKey.setFieldFP(p, (short) 0, (short) p.length);
pubKey.setA(a, (short) 0, (short) a.length);
pubKey.setB(b, (short) 0, (short) b.length);
pubKey.setG(G, (short) 0, (short) G.length);
pubKey.setR(r, (short) 0, (short) r.length);
byte[] pubData = {0x04, 0x00, (byte)0xb9, (byte)0x8f, (byte)0xcf, (byte)0xc3, (byte)0xc0, (byte)0xae, (byte)0x95, 0x6a, 0x5b, 0x12, 0x6d, (byte)0xbe, 0x43, (byte)0xe4, 0x7f, 0x09, 0x0d, (byte)0xde, 0x02, (byte)0xd2, 0x6b, 0x28, (byte)0x86, (byte)0xed, 0x2b, (byte)0xd7, (byte)0xe2, (byte)0xc2, 0x69, (byte)0xc1, (byte)0x89, (byte)0xb2, 0x53, (byte)0x96, (byte)0xc1, 0x2d, (byte)0xbf, 0x4c, 0x30, (byte)0xae, (byte)0xd5, (byte)0xd5, 0x3c, (byte)0xb5, (byte)0xf9, 0x3b, 0x20, 0x37, (byte)0x83, (byte)0x88, (byte)0x9f, 0x34, 0x74, (byte)0xf5, 0x6c, (byte)0x97, 0x1e, 0x0a, (byte)0xa9, (byte)0xe7, (byte)0xfa, (byte)0xa6, 0x69};
pubKey.setW(pubData, (short) 0, (short)pubData.length);
Now I signature the message:
// the class Secp256r1 can be found in above link
pair = SecP256r1.newKeyPair();
ECPublicKey pubKey = (ECPublicKey) pair.getPublic();
ECPrivateKey privKey = (ECPrivateKey) pair.getPrivate();
byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
signature.init(pair.getPrivate(), Signature.MODE_SIGN);
byte[] signData = new byte[127];
short sendLen = signature.sign(data, (short) 0, (short) data.length, buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, sendLen);
I send several APDUs to call this code fragment. But every time I receive a differnt sign message. Why should this happened?
There are methods setW(...) on ECPublicKey and setS(...) on ECPrivateKey.
The tricky part is that your keyPair.getPublic() and keyPair.getPrivate() return general interfaces. You have to cast them:
KeyPair keyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
ECPublicKey pub = (ECPublicKey) keyPair.getPublic();
ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate();
pub.setW(pubBytes, (short) 0, (short) pubBytes.length);
priv.setS(privBytes, (short) 0, (short) privBytes.length);
//do not forget to set parameters of your curve to both private and public key HERE!!!
https://docs.oracle.com/javacard/3.0.5/api/javacard/security/ECPublicKey.html
void setW(byte[] buffer,
short offset,
short length)
throws CryptoException
Sets the point of the curve comprising the public key. The point
should be specified as an octet string as per ANSI X9.62. A specific
implementation need not support the compressed form, but must support
the uncompressed form of the point. The plain text data format is
big-endian and right-aligned (the least significant bit is the least
significant bit of last byte). Input parameter data is copied into the
internal representation.
https://docs.oracle.com/javacard/3.0.5/api/javacard/security/ECPrivateKey.html
void setS(byte[] buffer,
short offset,
short length)
throws CryptoException
Sets the value of the secret key. The plain text data format is
big-endian and right-aligned (the least significant bit is the least
significant bit of last byte). Input parameter data is copied into the
internal representation.
ANSWER to UPDATE:
Signatures based on an elliptic curve contain a random number, that is why you get a different result each time you compute a signature. It is a feature, not a bug.
I want to convert ANSI Escape sequence to IRC color sequence.
So I wrote a regular expression 1 \e\[([\d;]+)?m, however, shell_output_string.replaceFirst ("\\e\\[([\\d;]+)?m", "$1") will return both the matched substring and the rest of non-matched substrings.
Then I wrote regular expression 2 .*\e\[([\d;]+)?m.*, hope it can matches the whole string and replace it with the matched substring, however, replaceFirst (".*\\e\\[([\\d;]+)?m.*", "$1") returns empty string, but matches (".*\\e\\[([\\d;]+)?m.*") is true. What's wrong with this regular expression?
The following question is very similar to this question: Pattern/Matcher group() to obtain substring in Java?
Sample code
import java.util.regex.*;
public class AnsiEscapeToIrcEscape
{
public static void main (String[] args)
{
//# grep --color=always bot /etc/passwd
//
//bot:x:1000:1000:bot:/home/bot:/bin/bash
byte[] shell_output_array = {
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#1 - #11)
0x62, 0x6F, 0x74, // bot (#12 - #14)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#15 - #20)
0x3A, 0x78, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A, // :x:1000:1000: (#21 - #33)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#34 - #44)
0x62, 0x6F, 0x74, // bot (#45 - #47)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#48 - #53)
0x3A, 0x2F, 0x68, 0x6F, 0x6D, 0x65, 0x2F, // :/home/ (#54 - #60)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#61 - #71)
0x62, 0x6F, 0x74, // bot (#72 - #74)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#75 - #80)
0x3A, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x62, 0x61, 0x73, 0x68, // :/bin/bash (#81 - #90)
};
String shell_output = new String (shell_output_array);
System.out.println (shell_output);
System.out.println ("total " + shell_output_array.length + " bytes");
final String CSI_REGEXP = "\\e\\[";
final String CSI_SGR_REGEXP_First = CSI_REGEXP + "([\\d;]+)?m";
final String CSI_SGR_REGEXP = ".*" + CSI_SGR_REGEXP_First + ".*";
System.out.println (shell_output.replaceFirst(CSI_SGR_REGEXP_First, "$1"));
System.out.println (shell_output.replaceFirst(CSI_SGR_REGEXP, "$1"));
}
}
Regex's are greedy - that is, each pattern will try to match as much of the input as it can.
This means that when a pattern starts with .* , that part of the pattern will try to cover as much of the input text that it can - so effectively the forcing the remaining part of the pattern to try to find a match starting from the end of the input string working towards the front.
So, what's the first match for the rest of the pattern from the end of the string (or, if you prefer, what's the last substring that matches)? It's on the penultimate line of your input, and consists of just ^[m
That matches because the whole ([\d;]+) part of the pattern is made optional by the following ? .
In turn, this means that, since the final expression has no digits or ;, the $1 group is empty - hence you get empty string output.
At least, that's what I reckon without being near a Java machine to test it. Hope it helps.
The API of String's replaceFirst says :
replaceFirst
public String replaceFirst(String regex,
String replacement)
Replaces the first substring of this string that matches the given regular expression with the given replacement.
An invocation of this method of the form str.replaceFirst(regex, repl) yields exactly the same result as the expression
Pattern.compile(regex).matcher(str).replaceFirst(repl)
Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string; see Matcher.replaceFirst(java.lang.String). Use Matcher.quoteReplacement(java.lang.String) to suppress the special meaning of these characters, if desired.
Parameters:
regex - the regular expression to which this string is to be matched
replacement - the string to be substituted for the first match
Returns:
The resulting String
Throws:
PatternSyntaxException - if the regular expression's syntax is invalid
Since:
1.4
See Also:
Pattern
Please read the Note Part which specifies that the \ and $ may cause the result to be different.
You can use Pattern and Matcher instead.
Example
public class RegexMatches
{
public static void main( String args[] ){
// String to be scanned to find the pattern.
// String line = "This order was placed for QT3000! OK?";
// String pattern = "(.*)(\\d+)(.*)";
byte[] shell_output_array = {
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#1 - #11)
0x62, 0x6F, 0x74, // bot (#12 - #14)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#15 - #20)
0x3A, 0x78, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A, 0x31, 0x30, 0x30, 0x30, 0x3A, // :x:1000:1000: (#21 - #33)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#34 - #44)
0x62, 0x6F, 0x74, // bot (#45 - #47)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#48 - #53)
0x3A, 0x2F, 0x68, 0x6F, 0x6D, 0x65, 0x2F, // :/home/ (#54 - #60)
0x1B, 0x5B, 0x30, 0x31, 0x3B, 0x33, 0x31, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[01;31m^[[K (#61 - #71)
0x62, 0x6F, 0x74, // bot (#72 - #74)
0x1B, 0x5B, 0x6D, 0x1B, 0x5B, 0x4B, // ^[[m^[[K (#75 - #80)
0x3A, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x62, 0x61, 0x73, 0x68, // :/bin/bash (#81 - #90)
};
String line = new String (shell_output_array);
//String pattern = "(.*)(\\d+)(.*)";
final String CSI_REGEXP = "\\e\\[";
final String CSI_SGR_REGEXP_First = CSI_REGEXP + "([\\d;]+)?m";
final String CSI_SGR_REGEXP = ".*" + CSI_SGR_REGEXP_First + ".*";
// Create a Pattern object
Pattern r = Pattern.compile(CSI_SGR_REGEXP);
// Now create matcher object.
Matcher m = r.matcher(line);
while (m.find()) {
System.out.println(m.start() + " " + m.end());
System.out.println("Found value: " + m.group());
}
}
}