Skip to content

Commit

Permalink
Merge pull request #71 from iExecBlockchainComputing/hotfix/6.1.0
Browse files Browse the repository at this point in the history
Hotfix/6.1.0
  • Loading branch information
jeremyjams authored Nov 30, 2021
2 parents 5de43ed + e573fe9 commit 19bd580
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 52 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=6.0.0
iexecCommonVersion=5.4.0
version=6.1.0
iexecCommonVersion=5.9.0
nexusUser=
nexusPassword=
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ public class TeeChallenge {

public TeeChallenge(String taskId) throws Exception {
this.taskId = taskId;
this.credentials = new EthereumCredentials();
this.credentials = EthereumCredentials.generate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,15 @@ public void encryptChallengeKeys(TeeChallenge teeChallenge) {
EthereumCredentials credentials = teeChallenge.getCredentials();
if (!credentials.isEncrypted()) {
String encPrivateKey = encryptionService.encrypt(credentials.getPrivateKey());
String encPublicKey = encryptionService.encrypt(credentials.getPublicKey());
credentials.setEncryptedKeys(encPrivateKey, encPublicKey);
credentials.setEncryptedPrivateKey(encPrivateKey);
}
}

public void decryptChallengeKeys(TeeChallenge teeChallenge) {
EthereumCredentials credentials = teeChallenge.getCredentials();
if (credentials.isEncrypted()) {
String privateKey = encryptionService.decrypt(credentials.getPrivateKey());
String publicKey = encryptionService.decrypt(credentials.getPublicKey());
credentials.setPlainKeys(privateKey, publicKey);
credentials.setPlainTextPrivateKey(privateKey);
}
}
}
69 changes: 41 additions & 28 deletions src/main/java/com/iexec/sms/utils/EthereumCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,26 @@

package com.iexec.sms.utils;

import java.math.BigInteger;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import com.iexec.common.utils.CredentialsUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.utils.Numeric;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
* Domain entity
*/
@Data
@Getter
@NoArgsConstructor //for hibernate
@AllArgsConstructor
@Entity
public class EthereumCredentials {
Expand All @@ -42,33 +45,43 @@ public class EthereumCredentials {
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;

private String address;
private String privateKey;
private String publicKey;
private boolean isEncrypted; // private & public keys
private boolean isEncrypted;
/*
* Address is required since recovering from private key is not possible
* from an encrypted private key state.
*/
private String address;

public EthereumCredentials() throws Exception {
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
this.address = Numeric.prependHexPrefix(Keys.getAddress(ecKeyPair));
setPlainKeys(toHex(ecKeyPair.getPrivateKey()),
toHex(ecKeyPair.getPublicKey()));
private EthereumCredentials(String privateKey, String address) {
this.setPlainTextPrivateKey(privateKey);
this.address = address;
}

public void setPlainKeys(String privateKey, String publicKey) {
this.setKeys(privateKey, publicKey, false);
/**
* Build EthereumCredentials from a random private key (generated from a
* secure random source).
*
* @return Ethereum credentials
* @throws java.security.GeneralSecurityException exception if failed to
* generate credentials
*/
public static EthereumCredentials generate() throws java.security.GeneralSecurityException {
ECKeyPair randomEcKeyPair = Keys.createEcKeyPair();
String privateKey =
Numeric.toHexStringWithPrefixZeroPadded(randomEcKeyPair.getPrivateKey(),
Keys.PRIVATE_KEY_LENGTH_IN_HEX);//hex-string size of 32 bytes (64)
return new EthereumCredentials(privateKey, CredentialsUtils.getAddress(privateKey));
}

public void setEncryptedKeys(String privateKey, String publicKey) {
this.setKeys(privateKey, publicKey, true);
public void setPlainTextPrivateKey(String privateKey) {
this.privateKey = privateKey;
this.isEncrypted = false;
}

private void setKeys(String privateKey, String publicKey, boolean isEncrypted) {
public void setEncryptedPrivateKey(String privateKey) {
this.privateKey = privateKey;
this.publicKey = publicKey;
this.isEncrypted = isEncrypted;
this.isEncrypted = true;
}

private String toHex(BigInteger input) {
return Numeric.prependHexPrefix(input.toString(16));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ public class TeeChallengeServiceTests {

private final static String TASK_ID = "0x123";
private final static String PLAIN_PRIVATE = "plainPrivate";
private final static String PLAIN_PUBLIC = "plainPublic";
private final static String ENC_PRIVATE = "encPrivate";
private final static String ENC_PUBLIC = "encPublic";

@Mock
private TeeChallengeRepository teeChallengeRepository;
Expand All @@ -58,7 +56,7 @@ public void beforeEach() {

private TeeChallenge getEncryptedTeeChallengeStub() throws Exception {
TeeChallenge teeChallenge = new TeeChallenge(TASK_ID);
teeChallenge.getCredentials().setEncryptedKeys(ENC_PRIVATE, ENC_PUBLIC);
teeChallenge.getCredentials().setEncryptedPrivateKey(ENC_PRIVATE);
return teeChallenge;
}

Expand All @@ -68,67 +66,65 @@ public void shouldGetExistingChallengeWithoutDecryptingKeys() throws Exception {
when(teeChallengeRepository.findByTaskId(TASK_ID)).thenReturn(Optional.of(encryptedTeeChallengeStub));

Optional<TeeChallenge> oTeeChallenge = teeChallengeService.getOrCreate(TASK_ID, false);
assertThat(oTeeChallenge).isPresent();
assertThat(oTeeChallenge.get().getCredentials().getPrivateKey()).isEqualTo(ENC_PRIVATE);
assertThat(oTeeChallenge.get().getCredentials().getPublicKey()).isEqualTo(ENC_PUBLIC);
verify(encryptionService, never()).decrypt(anyString());
}

@Test
public void shouldGetExistingChallengeAndDecryptKeys() throws Exception {
TeeChallenge encryptedTeeChallengeStub = getEncryptedTeeChallengeStub();
when(teeChallengeRepository.findByTaskId(TASK_ID)).thenReturn(Optional.of(encryptedTeeChallengeStub));
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE, PLAIN_PUBLIC);
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE);

Optional<TeeChallenge> oTeeChallenge = teeChallengeService.getOrCreate(TASK_ID, true);
assertThat(oTeeChallenge).isPresent();
assertThat(oTeeChallenge.get().getCredentials().getPrivateKey()).isEqualTo(PLAIN_PRIVATE);
assertThat(oTeeChallenge.get().getCredentials().getPublicKey()).isEqualTo(PLAIN_PUBLIC);
verify(encryptionService, times(2)).decrypt(anyString());
verify(encryptionService, times(1)).decrypt(anyString());
}

@Test
public void shouldCreateNewChallengeWithoutDecryptingKeys() throws Exception {
TeeChallenge encryptedTeeChallengeStub = getEncryptedTeeChallengeStub();
when(teeChallengeRepository.findByTaskId(TASK_ID)).thenReturn(Optional.empty());
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE, ENC_PUBLIC);
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE);
when(teeChallengeRepository.save(any())).thenReturn(encryptedTeeChallengeStub);

Optional<TeeChallenge> oTeeChallenge = teeChallengeService.getOrCreate(TASK_ID, false);
assertThat(oTeeChallenge).isPresent();
assertThat(oTeeChallenge.get().getCredentials().getPrivateKey()).isEqualTo(ENC_PRIVATE);
assertThat(oTeeChallenge.get().getCredentials().getPublicKey()).isEqualTo(ENC_PUBLIC);
verify(encryptionService, never()).decrypt(anyString());
}

@Test
public void shouldCreateNewChallengeAndDecryptKeys() throws Exception {
TeeChallenge encryptedTeeChallengeStub = getEncryptedTeeChallengeStub();
when(teeChallengeRepository.findByTaskId(TASK_ID)).thenReturn(Optional.empty());
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE, ENC_PUBLIC);
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE);
when(teeChallengeRepository.save(any())).thenReturn(encryptedTeeChallengeStub);
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE, PLAIN_PUBLIC);
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE);

Optional<TeeChallenge> oTeeChallenge = teeChallengeService.getOrCreate(TASK_ID, true);
assertThat(oTeeChallenge).isPresent();
assertThat(oTeeChallenge.get().getCredentials().getPrivateKey()).isEqualTo(PLAIN_PRIVATE);
assertThat(oTeeChallenge.get().getCredentials().getPublicKey()).isEqualTo(PLAIN_PUBLIC);
}

@Test
public void shouldEncryptChallengeKeys() throws Exception {
TeeChallenge teeChallenge = new TeeChallenge(TASK_ID);
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE, ENC_PUBLIC);
when(encryptionService.encrypt(anyString())).thenReturn(ENC_PRIVATE);
teeChallengeService.encryptChallengeKeys(teeChallenge);

assertThat(teeChallenge.getCredentials().getPrivateKey()).isEqualTo(ENC_PRIVATE);
assertThat(teeChallenge.getCredentials().getPublicKey()).isEqualTo(ENC_PUBLIC);
}

@Test
public void shouldDecryptChallengeKeys() throws Exception {
TeeChallenge teeChallenge = new TeeChallenge(TASK_ID);
teeChallenge.getCredentials().setEncrypted(true);
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE, PLAIN_PUBLIC);
when(encryptionService.decrypt(anyString())).thenReturn(PLAIN_PRIVATE);

teeChallengeService.decryptChallengeKeys(teeChallenge);
assertThat(teeChallenge.getCredentials().getPrivateKey()).isEqualTo(PLAIN_PRIVATE);
assertThat(teeChallenge.getCredentials().getPublicKey()).isEqualTo(PLAIN_PUBLIC);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void shouldGetPostComputePalaemonTokens() throws Exception {
.thenReturn(Optional.of(storageSecret));

TeeChallenge challenge = TeeChallenge.builder()
.credentials(new EthereumCredentials())
.credentials(EthereumCredentials.generate())
.build();
when(teeChallengeService.getOrCreate(TASK_ID, true))
.thenReturn(Optional.of(challenge));
Expand Down
49 changes: 49 additions & 0 deletions src/test/java/com/iexec/sms/utils/EthereumCredentialsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2021 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.iexec.sms.utils;

import com.iexec.common.utils.BytesUtils;
import com.iexec.common.utils.EthAddress;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.Credentials;

import java.security.GeneralSecurityException;

import static org.junit.jupiter.api.Assertions.*;

class EthereumCredentialsTest {

@Test
void generate() throws GeneralSecurityException {
EthereumCredentials ethereumCredentials = EthereumCredentials.generate();
assertFalse(ethereumCredentials.isEncrypted());
assertTrue(BytesUtils.isNonZeroedBytes32(ethereumCredentials.getPrivateKey()));
String address = ethereumCredentials.getAddress();
assertTrue(EthAddress.validate(address)
&& BytesUtils.isNonZeroedHexStringWithPrefixAndProperBytesSize(address,
20)); // non zeroed
}

@Test
void shouldMatchAddressOfGeneratedCredentials() throws GeneralSecurityException {
EthereumCredentials generatedCredentials = EthereumCredentials.generate();
String expectedAddress =
Credentials.create(generatedCredentials.getPrivateKey()).getAddress();
assertEquals(expectedAddress, generatedCredentials.getAddress());
}

}

0 comments on commit 19bd580

Please sign in to comment.