So my problem is the following : I'm trying to implement in Java a way to encrypt a message M (like from 1 character to let's say 1000) with a password P, chosen by the user (let's say "4z327yU10p"). I then want to hide the message in an image using a Pseudo Random Number Generator (PRNG) to choose the pixels. My seed is the password.
Here's my approach :
sha3 on the password to get a 256b output to use as key
use AES with the previously generated key to get an encrypted message
use the output as a seed for my PRNG
For (1): is this possible for a short password?
For (2): can AES be used for small messages?
For (3): how can I have random number in the interval of my image ? (0,...,480000) because my algorithm gives me an int?
here's the code :
public void initSeed(String password){ //pour initier la seed avec le password
Message message = new Message();
message.initMessageASCII(password);
List <Integer> temp = message.getMsg();
byte[] vect = new byte[temp.size()];
for (int i=0; i< temp.size(); i++){
vect[i] = temp.get(i).byteValue();
}
this.seed = vect;
}
public void init() { //pour initier le remplissage du vecteur randList
SecureRandom random;
try {
random = SecureRandom.getInstance("SHA1PRNG"); //SHA1PRNG est un algorithme très efficace
random.setSeed(seed);
random.nextBytes(randList); //fonction pour créer les bytes aléatoires et les écrire dans "bytes"
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
I'll answer the separate questions (ask separate questions):
Yes, SHA-3 can be used for arbitrarily sized messages.
Yes, AES can be used for arbitrarily sized messages.
Random.nextInt(int).
You can see this as a consultants curse though, I gave you what you asked for instead of what you need. For instance, you don't need the (not yet standardized) SHA-3 but you should use a PBKDF instead.
Related
I'm working on a project : copy a file and check if the size are equals. If not, delete file and redo it (number of retries is defined)
public boolean copieFichierAvecRetry(FileObject copieFichierFile, FileObject fichierACopier, int nbRetry, int currentNbRetry)
throws InterruptedException, IOException {
logger.logInfo("Deplacement du fichier " + fichierACopier.getName().getBaseName(),
"de " + fichierACopier.getParent().getName().getPath() + " vers "
+ copieFichierFile.getParent().getName().getPath());
copieFichierFile.copyFrom(fichierACopier, Selectors.SELECT_SELF);
boolean tailleOk = false;
// Si le flag de vérification est à true on vérifie que les fichiers
// copies ont la même taille
try {
tailleOk = verificationTailleCorrespondantes(copieFichierFile, fichierACopier);
if (!tailleOk && currentNbRetry <= nbRetry){
logger.logInfo("Erreur lors de la verification de la taille, essai n°" + currentNbRetry, null);
copieFichierFile.delete();
currentNbRetry++;
copieFichierAvecRetry(copieFichierFile, fichierACopier, nbRetry, currentNbRetry);
}
} catch (IOException e) {
logger.logWarn("Erreur lors de la verification de la taille : ", e.getMessage());
tailleOk = false;
}
return tailleOk;
}
Here is the unit test for the non-recursive function :
public void testCopieFichier()
throws IOException, InterruptedException, URISyntaxException, TransfertFichierException {
socleUtil.setNbTentativeMaxTransfert(1);
String nomFichierSource = "test123.txt";
String nomFichierDestination = "testDownloadSuccess.xml";
File fileOrigine = new File(getClass().getResource(SocleConstantes.SLASH).getFile());
String cheminFichierDistantOrigine = fileOrigine.getPath();
File fileDestination = new File(getClass().getResource(SocleConstantes.SLASH).toURI());
String cheminFichierDistantDestination = fileDestination.getPath() + FILE_SEPARATOR + "download";
assertTrue(socleUtil.copieFichier(
socleUtil.findFileLocal(cheminFichierDistantDestination + "/" + nomFichierDestination),
socleUtil.findFileLocal(cheminFichierDistantOrigine + "/" + nomFichierSource)));
assertTrue(fileDestination.exists());
}
As you can see in the code above, it will copy a file, check size and if it's OK then return true.
If it's false for 5 times (in the exemple) the function calls itself after deleting the file with wrong size.
verificationTailleCorrespondantes is the function to compare sizes.
tailleOk is true if both files are same size.
How should I test the recursivity of this function if it copies a file and never fail (which happens in production) ?
Thanks
In this case, I'd write the following scenarios:
the process success at its first iteration
the process fails at its (n-1)th iteration, success at its nth iteration with n < number of retries
the process fails at its nth iteration with n == number of retries
In order to do it, you'll need to mock your dependencies. Specially the one checking the file size. The mocking for the previous scenarios would be
file size check returns true. Assert that the check was run once and the result is valid
file size check returns false (n-1) times and true the nth time. Assert that the check was run n times and the result is valid
file size check returns false. Assert that the check was run number of retries times and the result is invalid
I have written a SNMP listener in Java using the TNM4J library which uses the SNMP4J library.
The listener is able to read received traps, except for traps that appear to be indexed in a table.
The listener is listening to traps from an Ericsson object, which means I am using the ERICSSON-ALARM-MIB and the MIB imports it needs. The trap I am receiving is the eriAlarmActiveManagedObject with OID .1.3.6.1.4.1.193.183.4.1.3.5.1.5, but I also tested it locally with the other traps in the table and the same error occurs
If one looks at https://mibs.observium.org/mib/ERICSSON-ALARM-MIB/ :
All the traps that are from a table like this can not be read by the listener.
It gives an index out of bound exception from a extractIndexes method in MibbleIndexExtractor.java in the TNM4J library.
#Override
public IndexDescriptor[] extractIndexes(String instanceOid) {
String oid = symbol.getValue().toString();
String suboid = instanceOid.substring(oid.length() + 1);
int[] components = oidToArray(suboid);
int offset = 0;
IndexDescriptor[] descriptors = new IndexDescriptor[indexes.length];
for (int i = 0; i < indexes.length; i++) {
SnmpIndex index = indexes[i];
MibValueSymbol indexSymbol = symbol.getMib().getSymbolByOid(index.getValue().toString());
MibType indexType = ((SnmpObjectType) indexSymbol.getType()).getSyntax();
int length = fixedLength(indexType);
boolean implied = length != -1 || index.isImplied();
if (length == -1) {
length = variableLength(indexType, components, offset, index.isImplied());
}
int[] encoded = new int[length];
System.arraycopy(components, offset, encoded, 0, length);
descriptors[i] = new MibbleIndexDescriptor(indexSymbol, encoded, implied);
offset += length;
}
return descriptors;
}
I have debugged it and this happens because the oid String and instanceOid String are identical which of course causes an exception where the suboid String is being created.
However on all other traps it never calls this extractIndexes method, but just works finely and prints out the trap and oid name correctly.
Any suggestion on how to fix this issue?
After being in contact with the developer of TNM4J he made some fixes to his library.
After that the Ericsson oids was being correctly translated. There was a few missing translations from oids, which was because of the loading order of the MIBs.
Re-adjusting these made it work.
For anyone interested the troubleshooting process with the developer can view it here:
https://github.com/soulwing/tnm4j/issues/9
I am working on automating a sign up that contains a counter.
So the thing is, I want to sign up to something that occurs every 7 minutes.
Here is what the web code looks like:
<class-countdown-timer _ngcontent-c19="" _nghost-c24="">
<!---->
<h2 _ngcontent-c24="" id="class-countdown-timer">Próxima clase en vivo en <span _ngcontent-c24="" class="countdown-timer">02:15</span>
<i _ngcontent-c24="" aria-hidden="true" class="icon-clock"></i>
</h2>
</class-countdown-timer>
My issue is that the "class-countdown-timer" text is dynamic and the "countdown-timer" its a countdown, from 07:00 to 00:00.
My cry for help is that I need to perform a certain action when the "class-countdown-timer" text is "Próxima clase en vivo en " and the counter is in between "05:00" and "02:00"
I can't get to work a fluent wait that waits until first, countdown text shows the above and the timer is between those times, any idea?
thanks :D
Try the below code :
// Count-down timer for looping upto 8 minutes
int countdown = 480;
while(countdown-->0) {
// Fetching the actual class-countdown-timer value
String actualTimerText = driver.findElement(By.id("class-countdown-timer")).getText().trim();
String expectedTimerText = "Próxima clase en vivo en ";
// Fetching the actual countdown-timer value
String countdownTimer = driver.findElement(By.xpath("//span[#class='countdown-timer']")).getText().trim();
// Converting the time for better comparing
SimpleDateFormat format = new SimpleDateFormat("hh:mm");
Date expectedFirstTime = format.parse("05:00"), expectedSecondTime = format.parse("02:00");
Date actualCountdownTimer = format.parse(countdownTimer);
// Checking the condition if the 'class-countdown-timer' text is 'Próxima clase en vivo ee' and counter is in between '05:00' and '02:00' or not?
if(actualTimerText.equals(expectedTimerText) && ((actualCountdownTimer.equals(expectedSecondTime) || actualCountdownTimer.after(expectedSecondTime)) && (actualCountdownTimer.equals(expectedFirstTime) || actualCountdownTimer.before(expectedFirstTime)))) {
System.out.println("Condition Satisfied...");
// Do something
break;
}
// Waiting for one second before finding the element and checking the condition
Thread.sleep(1000);
}
The above approach is using the looping concept, iterate up to 8 minutes(480 seconds) until the required condition get satisfied.
Is there a Java library/example to read an openssh format ecdsa public key to a JCE PublicKey in Java? I want to use EC for JWT .
The format I'm trying to read is as per authorized_keys, or Github API (e.g. https://api.github.com/users/davidcarboni/keys): ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK8hPtB72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM=
I've found this answer, which is fine for RSA and DSS:
Using public key from authorized_keys with Java security, and this discussion of the openssh format for ECDSA: https://security.stackexchange.com/questions/129910/ecdsa-why-do-ssh-keygen-and-java-generated-public-keys-have-different-sizes
However I'm getting lost trying to adapt the RSS/DSA code for ECDSA - I'm not sure how to set up an ECPublicKeySpec. It needs ECPoint, EllipticCurve, ECParameterSpec, ECField. The openssh format only contains two integers, which makes sense for ECPoint, but I don't know how to set up the rest.
I've been poking around a bunch of libraries, including jsch, sshj, ssh-tools and good old Bouncycastle. The closest I have is:
com.jcraft.jsch.KeyPair load = com.jcraft.jsch.KeyPair.load(jsch, null, bytes[openSshKey]);
Which loads the key fine, but doesn't get me to a JCE PublicKey - just a byte[] getPublicKeyBlob() method.
Am I missing something obvious?
I've found a way to do this using Bouncycastle (but would like to find a JCE way).
Adapting the code from Using public key from authorized_keys with Java security, and refering to RFC 5656, section 3.1, the following block added to decodePublicKey will parse the single BigInt value Q, which is "the public key encoded from an elliptic curve point":
if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://www.rfc-editor.org/rfc/rfc5656#section-3.1)
// The string [identifier] is the identifier of the elliptic curve
// domain parameters. The format of this string is specified in
// Section 6.1 (https://www.rfc-editor.org/rfc/rfc5656#section-6.1).
// Information on the REQUIRED and RECOMMENDED sets of
// elliptic curve domain parameters for use with this algorithm can be
// found in Section 10 (https://www.rfc-editor.org/rfc/rfc5656#section-10).
String identifier = decodeType();
if (!type.endsWith(identifier)) {
throw new IllegalArgumentException("Invalid identifier " + identifier + " for key type " + type + ".");
}
// Q is the public key encoded from an elliptic curve point into an
// octet string as defined in Section 2.3.3 of [SEC1];
// (https://www.rfc-editor.org/rfc/rfc5656#ref-SEC1)
// point compression MAY be used.
BigInteger q = decodeBigInt();
ECPublicKey keyBC = getKeyBC(q, identifier);
return keyBC;
}
The solution I've found for getting from Q to an ECPublicKey is the following, using the Bouncycastle API (credit to Generate ECPublicKey from ECPrivateKey for providing the starting point):
ECPublicKey getKeyBC(BigInteger q, String identifier) {
// https://stackoverflow.com/questions/42639620/generate-ecpublickey-from-ecprivatekey
try {
// This only works with the Bouncycastle library:
Security.addProvider(new BouncyCastleProvider());
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec);
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(pubSpec);
return publicKey;
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
}
That gets you from an openssh format elliptic curve public key (ssh-keygen -t ecdsa -b [256|384|521]) to a JCE ECPublicKey.
For completeness, here's the code I've gone with. It's nearly-pure JCE, with a sprinkling of Bouncycastle inside helper methods (this updates the example code in Using public key from authorized_keys with Java security):
...
} else if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
String identifier = decodeType();
BigInteger q = decodeBigInt();
ECPoint ecPoint = getECPoint(q, identifier);
ECParameterSpec ecParameterSpec = getECParameterSpec(identifier);
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
return KeyFactory.getInstance("EC").generatePublic(spec);
} ...
/**
* Provides a means to get from a parsed Q value to the X and Y point values.
* that can be used to create and ECPoint compatible with ECPublicKeySpec.
*
* #param q According to RFC 5656:
* "Q is the public key encoded from an elliptic curve point into an octet string"
* #param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* #return An ECPoint suitable for creating a JCE ECPublicKeySpec.
*/
ECPoint getECPoint(BigInteger q, String identifier) {
String name = identifier.replace("nist", "sec") + "r1";
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
BigInteger x = point.getAffineXCoord().toBigInteger();
BigInteger y = point.getAffineYCoord().toBigInteger();
System.out.println("BC x = " + x);
System.out.println("BC y = " + y);
return new ECPoint(x, y);
}
/**
* Gets the curve parameters for the given key type identifier.
*
* #param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* #return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec.
*/
ECParameterSpec getECParameterSpec(String identifier) {
try {
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Unable to get parameter spec for identifier " + identifier, e);
}
}
I have a bunch of Gemalto java cards and as you see below, I'm okay with mutual authentication process using GlobalPlatformPro:
C:\globalPlatformPro> gp -visa2 -key 47454d5850524553534f53414d504c45 -list -debug -verbose -info
Reader: ACS ACR1281 1S Dual Reader ICC 0
ATR: 3B7D96000080318065B0831111E583009000
A>> 00A40400 00
A<< 6F198408A000000018434D00A50D9F6E061291921101009F6501FF 9000
***** Card info:
A>> 80CA9F7F 00
A<< 9F7F2A4090612812919211010041849D08192420C3033241840333418403344184000003250000000000000000 9000
***** KEY INFO
A>> 80CA00E0 00
A<< E012C00401FF8010C00402FF8010C00403FF8010 9000
VER:255 ID:1 TYPE:DES3 LEN:16
VER:255 ID:2 TYPE:DES3 LEN:16
VER:255 ID:3 TYPE:DES3 LEN:16
Key version suggests factory keys
A>> 80500000 08 2CA286A611F6CAFD 00
A<< 4D0041849D08192420C3FF0131D644E9913234DDE1F0A6A462C71805 9000
A>> 84820100 10 CC2D0CC35F6BD64F816A774D3ADB18F2
A<< 9000
//Useless lines for censored!
C:\globalPlatformPro>
As VISA documents are not publicly available, I took a look at GlobalPlatformPro source code to find out how the key diversification happens in for visa2, and I found these methods there:
public static GPKeySet diversify(GPKeySet keys, byte[] diversification_data, Diversification mode, int scp) throws GPException {
try {
GPKeySet result = new GPKeySet();
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
for (KeyType v : KeyType.values()) {
if (v == KeyType.RMAC)
continue;
byte [] kv = null;
// shift around and fill initialize update data as required.
if (mode == Diversification.VISA2) {
kv = fillVisa(diversification_data, v);
} else if (mode == Diversification.EMV) {
kv = fillEmv(diversification_data, v);
}
// Encrypt with current master key
cipher.init(Cipher.ENCRYPT_MODE, keys.getKey(v).getKey(Type.DES3));
byte [] keybytes = cipher.doFinal(kv);
// Replace the key, possibly changing type. G&D SCE 6.0 uses EMV 3DES and resulting keys
// must be interpreted as AES-128
GPKey nk = new GPKey(keybytes, scp == 3 ? Type.AES : Type.DES3);
result.setKey(v, nk);
}
return result;
} catch (BadPaddingException |InvalidKeyException | IllegalBlockSizeException e) {
throw new GPException("Diversification failed.", e);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("Diversification failed.", e);
}
}
public static byte[] fillVisa(byte[] init_update_response, KeyType key) {
byte[] data = new byte[16];
System.arraycopy(init_update_response, 0, data, 0, 2);
System.arraycopy(init_update_response, 4, data, 2, 4);
data[6] = (byte) 0xF0;
data[7] = key.getValue();
System.arraycopy(init_update_response, 0, data, 8, 2);
System.arraycopy(init_update_response, 4, data, 10, 4);
data[14] = (byte) 0x0F;
data[15] = key.getValue();
return data;
}
So I tried to repeat the host cryptogram generation for above communication. I have:
Master Key = 47454d5850524553534f53414d504c45
Based on GlobalPlatform v 2.3 Card Specification:
Host_Challenge = 2CA286A611F6CAFD
INITIAL UPDATE response: 4D0041849D08192420C3 FF01 31D644E9913234DD E1F0A6A462C71805
Key Diversification Data = 4D0041849D08192420C3
Key Information = FF01 : So SCP01 is used.
Card Challenge = 31D644E9913234DD
Card Cryptogram = E1F0A6A462C71805
So, based on the GPP source code above:
Diversification_Data = 4D00 9D081924 F001 4D00 9D081924 0F01
And then the Static ENC Key is:
Static_ENC = Encrypt(MasterKey, Diversification_Data )
So, using this online tool, I have:
It means:
Static_ENC_KEY = 84f2a84ecdade8cacc9e7e07faebe4e6
To calculate ENC Session Key, I used GlobalPlatform Specification again:
So I have:
Derivation_Data = 913234DD 2CA286A6 31D644E9 11F6CAFD
And so the ENC_Session_Key is:
ENC_Session_Key = b1ed5ea3f69978274d2ffe0de467ec1c
Finally, The generation and verification of the host cryptogram is performed by concatenating the 8-byte card challenge and 8-byte host challenge resulting in a 16-byte block and concatenating this 16-byte array with 80 00 00 00 00 00 00 00. Then signing this with the ENC session key in CBC mode with a zero ICV:
Data2Encrypt = 31D644E9913234DD 2CA286A611F6CAFD 8000000000000000
And I have:
Well, I tried above steps twice and each time, at the end I was faced with a wrong host_cryptogram value! But when I repeat the steps and wrote those line by line in my question, I finally noticed that the final result that I have is equal with the GPP result at the first of my question! So instead of deleting my question, I preferred to keep it here for future viewers.
So to conclusion:
Having key diversification schemes in a smart card, adds one step to those steps that is mentioned in GlobalPlatform Card Specification for calculating Card Cryptogram and MAC values. And that step is calculating Static Keys.
Diversification_Data for Static Keys calculation are (source):
First two bytes of INITAL UPDATE response data is the same xxh xxh and bytes[4:8] of it are IC Serial Number.
Encrypting Diversification data using Triple DES Algorithm in ECB mode with Master Key, returns Static Keys.
For check the card cryptogram you have to concatenating the 8-byte of host challenge and the 8-byte of card challenge and "8000000000000000".
after make the string, Then signing this with the ENC session key in CBC mode with a zero ICV.