From 3e62ad946d25361233eff83e82f2a7ddd72aca2a Mon Sep 17 00:00:00 2001 From: john Date: Mon, 24 Nov 2025 15:59:13 -0700 Subject: [PATCH] chore(*): restore from backup this project was archived and never moved to my new gittea instance, until now --- .gitignore | 12 ++ .vscode/settings.json | 5 + README.md | 1 + pom.xml | 96 ++++++++++ .../jkgroller/cryptonote/CryptonoteApi.java | 20 ++ .../cryptonote/config/KeyGeneratorConfig.java | 64 +++++++ .../config/PasswordEncoderConfig.java | 34 ++++ .../cryptonote/config/SecurityConfig.java | 44 +++++ .../converter/AccountEntityConverter.java | 15 ++ .../converter/AccountTOConverter.java | 23 +++ .../converter/NoteEntityConverter.java | 13 ++ .../converter/NoteResourceConverter.java | 20 ++ .../cryptonote/converter/NoteTOConverter.java | 15 ++ .../cryptonote/entity/AccountEntity.java | 177 ++++++++++++++++++ .../cryptonote/entity/NoteEntity.java | 145 ++++++++++++++ .../repository/AccountEntityRepository.java | 15 ++ .../repository/NoteEntityRepository.java | 9 + .../cryptonote/enums/AccountRole.java | 9 + .../cryptonote/resource/Account.java | 36 ++++ .../cryptonote/resource/NoteResource.java | 83 ++++++++ .../resource/UserAccountResource.java | 7 + .../attribute/CredentialsAttribute.java | 43 +++++ .../repository/NoteResourceRepository.java | 73 ++++++++ .../UserAccountResourceRepository.java | 103 ++++++++++ .../cryptonote/service/AccountService.java | 22 +++ .../service/AccountServiceImpl.java | 138 ++++++++++++++ .../cryptonote/service/CipherService.java | 27 +++ .../cryptonote/service/CipherServiceImpl.java | 70 +++++++ .../cryptonote/service/NoteService.java | 13 ++ .../cryptonote/service/NoteServiceImpl.java | 123 ++++++++++++ .../cryptonote/service/to/AccountTO.java | 78 ++++++++ .../to/CreateNewAccountResponseTO.java | 18 ++ .../to/CreateNewUserAccountResponseTO.java | 19 ++ .../service/to/CreateNoteRequestTO.java | 78 ++++++++ .../service/to/CreateNoteResponseTO.java | 23 +++ .../service/to/DecryptRequestTO.java | 60 ++++++ .../service/to/DecryptResponseTO.java | 35 ++++ .../service/to/EncryptRequestTO.java | 79 ++++++++ .../service/to/EncryptResponseTO.java | 44 +++++ .../cryptonote/service/to/NoteTO.java | 55 ++++++ .../to/RetrieveUserAccountRequestTO.java | 39 ++++ .../to/RetrieveUserAccountResponseTO.java | 19 ++ src/main/resources/application.properties | 30 +++ src/test/resources/db.sql | 58 ++++++ 44 files changed, 2090 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/jkgroller/cryptonote/CryptonoteApi.java create mode 100644 src/main/java/com/jkgroller/cryptonote/config/KeyGeneratorConfig.java create mode 100644 src/main/java/com/jkgroller/cryptonote/config/PasswordEncoderConfig.java create mode 100644 src/main/java/com/jkgroller/cryptonote/config/SecurityConfig.java create mode 100644 src/main/java/com/jkgroller/cryptonote/converter/AccountEntityConverter.java create mode 100644 src/main/java/com/jkgroller/cryptonote/converter/AccountTOConverter.java create mode 100644 src/main/java/com/jkgroller/cryptonote/converter/NoteEntityConverter.java create mode 100644 src/main/java/com/jkgroller/cryptonote/converter/NoteResourceConverter.java create mode 100644 src/main/java/com/jkgroller/cryptonote/converter/NoteTOConverter.java create mode 100644 src/main/java/com/jkgroller/cryptonote/entity/AccountEntity.java create mode 100644 src/main/java/com/jkgroller/cryptonote/entity/NoteEntity.java create mode 100644 src/main/java/com/jkgroller/cryptonote/entity/repository/AccountEntityRepository.java create mode 100644 src/main/java/com/jkgroller/cryptonote/entity/repository/NoteEntityRepository.java create mode 100644 src/main/java/com/jkgroller/cryptonote/enums/AccountRole.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/Account.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/NoteResource.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/UserAccountResource.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/attribute/CredentialsAttribute.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/repository/NoteResourceRepository.java create mode 100644 src/main/java/com/jkgroller/cryptonote/resource/repository/UserAccountResourceRepository.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/AccountService.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/AccountServiceImpl.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/CipherService.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/CipherServiceImpl.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/NoteService.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/NoteServiceImpl.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/AccountTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/CreateNewAccountResponseTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/CreateNewUserAccountResponseTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteRequestTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteResponseTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/DecryptRequestTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/DecryptResponseTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/EncryptRequestTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/EncryptResponseTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/NoteTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountRequestTO.java create mode 100644 src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountResponseTO.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/resources/db.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b2c130 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/target/ +/build/ +/.classpath +/.project + .settings/ +/cryptonote.log +/.idea +/bin/ +.springBeans +cryptonote.iml +mvnw +mvnw.cmd diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0ac76ba --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "conventionalCommits.scopes": [ + "*" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b2b456 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Placeholder for something eventually meaningful. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..4496d3e --- /dev/null +++ b/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + com.jkgroller.cryptonote + cryptonote-api + 2.0.0-SNAPSHOT + jar + cryptonote-api + API for encrypting notes. + + + org.springframework.boot + spring-boot-starter-parent + 2.2.5.RELEASE + + + + UTF-8 + UTF-8 + 13 + 3.1.20191113192440 + 1.14 + 1.3.1.Final + + + + + jcenter + https://jcenter.bintray.com/ + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-devtools + + + io.crnk + crnk-setup-spring-boot2 + ${crnk.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + + cryptonote-api + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + + + diff --git a/src/main/java/com/jkgroller/cryptonote/CryptonoteApi.java b/src/main/java/com/jkgroller/cryptonote/CryptonoteApi.java new file mode 100644 index 0000000..d9d6d58 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/CryptonoteApi.java @@ -0,0 +1,20 @@ +package com.jkgroller.cryptonote; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * + */ +@SpringBootApplication +public class CryptonoteApi { + + /** + * @param args + */ + public static void main(String[] args) { + SpringApplication.run(CryptonoteApi.class, args); + } + +} + diff --git a/src/main/java/com/jkgroller/cryptonote/config/KeyGeneratorConfig.java b/src/main/java/com/jkgroller/cryptonote/config/KeyGeneratorConfig.java new file mode 100644 index 0000000..d17dc4c --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/config/KeyGeneratorConfig.java @@ -0,0 +1,64 @@ +package com.jkgroller.cryptonote.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.keygen.BytesKeyGenerator; +import org.springframework.security.crypto.keygen.KeyGenerators; + +@Configuration +public class KeyGeneratorConfig { + + private final int ENCRYPTION_KEY_LENGTH; + + private final int USERNAME_LENGTH; + + private final int PASSWORD_LENGTH; + + private final int IDENTIFIER_LENGTH; + + /** + * This is how you inject a value from a properties file into a constant. + */ + public KeyGeneratorConfig(@Value("${encryption.key.length}") int encryptKeyLength + , @Value("${username.length}") int userNameLength + , @Value("${password.length}") int passwordLength + , @Value("${identifier.length}") int identifierLength) { + this.ENCRYPTION_KEY_LENGTH = encryptKeyLength; + this.USERNAME_LENGTH = userNameLength; + this.PASSWORD_LENGTH = passwordLength; + this.IDENTIFIER_LENGTH = identifierLength; + } + + /** + * @return + */ + @Bean(name = "encryptionKeyGenerator") + public BytesKeyGenerator encryptionKeyGenerator() { + return KeyGenerators.secureRandom(ENCRYPTION_KEY_LENGTH); + } + + /** + * @return + */ + @Bean(name = "userNameGenerator") + public BytesKeyGenerator userNameGenerator() { + return KeyGenerators.secureRandom(USERNAME_LENGTH); + } + + /** + * @return + */ + @Bean(name = "passwordGenerator") + public BytesKeyGenerator passwordGenerator() { + return KeyGenerators.secureRandom(PASSWORD_LENGTH); + } + + /** + * @return + */ + @Bean(name = "identifierGenerator") + public BytesKeyGenerator identifierGenerator() { + return KeyGenerators.secureRandom(IDENTIFIER_LENGTH); + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/config/PasswordEncoderConfig.java b/src/main/java/com/jkgroller/cryptonote/config/PasswordEncoderConfig.java new file mode 100644 index 0000000..890d963 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/config/PasswordEncoderConfig.java @@ -0,0 +1,34 @@ +package com.jkgroller.cryptonote.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * + */ +@Configuration +public class PasswordEncoderConfig { + + private final int PASSWORD_ENCRYPTION_STRENGTH; + + /** + * This is how you inject a value from a properties file into a constant. + */ + public PasswordEncoderConfig(@Value("${password.encryption.strength}") int passwordEncryptionStrength) { + this.PASSWORD_ENCRYPTION_STRENGTH = passwordEncryptionStrength; + } + + /** + * + * @return + */ + @Bean + public PasswordEncoder createPasswordEncoderBean() { + return new BCryptPasswordEncoder(PASSWORD_ENCRYPTION_STRENGTH); + } + + +} diff --git a/src/main/java/com/jkgroller/cryptonote/config/SecurityConfig.java b/src/main/java/com/jkgroller/cryptonote/config/SecurityConfig.java new file mode 100644 index 0000000..b7a3822 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/config/SecurityConfig.java @@ -0,0 +1,44 @@ +package com.jkgroller.cryptonote.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +/** + * + */ +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + //... + } + + /** + * + * @param httpSecurity + * @throws Exception + */ + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + //httpSecurity.authorizeRequests().antMatchers("/v1/userAccounts/**").permitAll(); + } + + /** + * + * @param web + * @throws Exception + */ + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/v1/userAccounts/**", "/h2/**", "/v1/notes/**"); + } + + +} diff --git a/src/main/java/com/jkgroller/cryptonote/converter/AccountEntityConverter.java b/src/main/java/com/jkgroller/cryptonote/converter/AccountEntityConverter.java new file mode 100644 index 0000000..ae4e09f --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/converter/AccountEntityConverter.java @@ -0,0 +1,15 @@ +package com.jkgroller.cryptonote.converter; + +import com.jkgroller.cryptonote.entity.AccountEntity; +import com.jkgroller.cryptonote.service.to.AccountTO; +import org.mapstruct.Mapper; + +/** + * + */ +@Mapper(componentModel = "spring") +public interface AccountEntityConverter { + + AccountTO accountEntityToAccountTO(AccountEntity accountEntity); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/converter/AccountTOConverter.java b/src/main/java/com/jkgroller/cryptonote/converter/AccountTOConverter.java new file mode 100644 index 0000000..0acab94 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/converter/AccountTOConverter.java @@ -0,0 +1,23 @@ +package com.jkgroller.cryptonote.converter; + +import com.jkgroller.cryptonote.resource.UserAccountResource; +import com.jkgroller.cryptonote.service.to.AccountTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * + */ +@Mapper(componentModel = "spring") +public interface AccountTOConverter { + + /** + * + * @param accountTO + * @return + */ + @Mapping(target = "credentialsAttribute.userName", source = "accountTO.userName") + @Mapping(target = "credentialsAttribute.password", source = "accountTO.password") + UserAccountResource accountTOToUserAccountResource(AccountTO accountTO); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/converter/NoteEntityConverter.java b/src/main/java/com/jkgroller/cryptonote/converter/NoteEntityConverter.java new file mode 100644 index 0000000..9eed0c8 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/converter/NoteEntityConverter.java @@ -0,0 +1,13 @@ +package com.jkgroller.cryptonote.converter; + +import org.mapstruct.Mapper; + +/** + * + */ +@Mapper(componentModel = "spring") +public interface NoteEntityConverter { + + //NoteTO noteEntityToNoteTO(NoteEntity noteEntity); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/converter/NoteResourceConverter.java b/src/main/java/com/jkgroller/cryptonote/converter/NoteResourceConverter.java new file mode 100644 index 0000000..a196c7f --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/converter/NoteResourceConverter.java @@ -0,0 +1,20 @@ +package com.jkgroller.cryptonote.converter; + +import com.jkgroller.cryptonote.resource.NoteResource; +import com.jkgroller.cryptonote.service.to.CreateNoteRequestTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * + */ +@Mapper(componentModel = "spring") +public interface NoteResourceConverter { + + @Mapping(target = "userName", source = "credentialsAttribute.userName") + @Mapping(target = "password", source = "credentialsAttribute.password") + @Mapping(target = "noteName", source = "name") + @Mapping(target = "noteContents", source = "contents") + CreateNoteRequestTO noteResourceToCreateEncryptedNoteRequestTO(NoteResource noteResource); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/converter/NoteTOConverter.java b/src/main/java/com/jkgroller/cryptonote/converter/NoteTOConverter.java new file mode 100644 index 0000000..ccc0d2b --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/converter/NoteTOConverter.java @@ -0,0 +1,15 @@ +package com.jkgroller.cryptonote.converter; + +import com.jkgroller.cryptonote.resource.NoteResource; +import com.jkgroller.cryptonote.service.to.NoteTO; +import org.mapstruct.Mapper; + +/** + * + */ +@Mapper(componentModel = "spring") +public interface NoteTOConverter { + + NoteResource noteTOToNoteResource(NoteTO noteTO); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/entity/AccountEntity.java b/src/main/java/com/jkgroller/cryptonote/entity/AccountEntity.java new file mode 100644 index 0000000..64d5b5e --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/entity/AccountEntity.java @@ -0,0 +1,177 @@ +package com.jkgroller.cryptonote.entity; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity(name = "account") +public class AccountEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(nullable = false) + private String identifier; + + @Column(nullable = false) + private String userName; + + @Column(nullable = false) + private String passwordHash; + + @Column(nullable = false) + private byte[] encryptedSurrogateKey; + + @Column(nullable = false) + private byte[] surrogateKeySalt; + + @Column(nullable = false) + private String role; + + @Column(nullable = false) + private LocalDateTime creationDateTime; + + @Column(nullable = false) + private LocalDateTime lastLoginDateTime; + + /** + * @return + */ + public Integer getId() { + return id; + } + + /** + * + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * + * @return + */ + public String getUserName() { + return userName; + } + + /** + * + * @param userName + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * + * @return + */ + public String getPasswordHash() { + return passwordHash; + } + + /** + * + * @param passwordHash + */ + public void setPasswordHash(String passwordHash) { + this.passwordHash = passwordHash; + } + + /** + * + * @return + */ + public String getRole() { + return role; + } + + /** + * + * @param role + */ + public void setRole(String role) { + this.role = role; + } + + /** + * + * @return + */ + public String getIdentifier() { + return identifier; + } + + /** + * + * @param identifier + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * + * @return + */ + public LocalDateTime getCreationDateTime() { + return creationDateTime; + } + + /** + * + * @param creationDateTime + */ + public void setCreationDateTime(LocalDateTime creationDateTime) { + this.creationDateTime = creationDateTime; + } + + /** + * + * @return + */ + public byte[] getEncryptedSurrogateKey() { + return encryptedSurrogateKey; + } + + /** + * + * @param encryptedSurrogateKey + */ + public void setEncryptedSurrogateKey(byte[] encryptedSurrogateKey) { + this.encryptedSurrogateKey = encryptedSurrogateKey; + } + + /** + * @return + */ + public LocalDateTime getLastLoginDateTime() { + return lastLoginDateTime; + } + + /** + * @param lastLoginDateTime + */ + public void setLastLoginDateTime(LocalDateTime lastLoginDateTime) { + this.lastLoginDateTime = lastLoginDateTime; + } + + /** + * + * @return + */ + public byte[] getSurrogateKeySalt() { + return surrogateKeySalt; + } + + /** + * + * @param surrogateKeySalt + */ + public void setSurrogateKeySalt(byte[] surrogateKeySalt) { + this.surrogateKeySalt = surrogateKeySalt; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/entity/NoteEntity.java b/src/main/java/com/jkgroller/cryptonote/entity/NoteEntity.java new file mode 100644 index 0000000..6a671a1 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/entity/NoteEntity.java @@ -0,0 +1,145 @@ +package com.jkgroller.cryptonote.entity; + +import javax.persistence.*; + +@Entity(name = "note") +public class NoteEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(nullable = false) + private String identifier; + + @Column(nullable = false) + private byte[] key; + + @Column(nullable = false) + private byte[] keySalt; + + @Column(nullable = false) + private byte[] name; + + @Column(nullable = false) + private byte[] nameSalt; + + @Column(nullable = false) + private byte[] contents; + + @Column(nullable = false) + private byte[] contentsSalt; + + /** + * @return + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * @return + */ + public String getIdentifier() { + return identifier; + } + + /** + * @param identifier + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * @return + */ + public byte[] getKey() { + return key; + } + + /** + * @param key + */ + public void setKey(byte[] key) { + this.key = key; + } + + + /** + * @return + */ + public byte[] getName() { + return name; + } + + /** + * @param name + */ + public void setName(byte[] name) { + this.name = name; + } + + /** + * @return + */ + public byte[] getContents() { + return contents; + } + + /** + * @param contents + */ + public void setContents(byte[] contents) { + this.contents = contents; + } + + /** + * @return + */ + public byte[] getKeySalt() { + return keySalt; + } + + /** + * @param keySalt + */ + public void setKeySalt(byte[] keySalt) { + this.keySalt = keySalt; + } + + /** + * @return + */ + public byte[] getNameSalt() { + return nameSalt; + } + + /** + * @param nameSalt + */ + public void setNameSalt(byte[] nameSalt) { + this.nameSalt = nameSalt; + } + + /** + * @return + */ + public byte[] getContentsSalt() { + return contentsSalt; + } + + /** + * @param contentsSalt + */ + public void setContentsSalt(byte[] contentsSalt) { + this.contentsSalt = contentsSalt; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/entity/repository/AccountEntityRepository.java b/src/main/java/com/jkgroller/cryptonote/entity/repository/AccountEntityRepository.java new file mode 100644 index 0000000..df05ae3 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/entity/repository/AccountEntityRepository.java @@ -0,0 +1,15 @@ +package com.jkgroller.cryptonote.entity.repository; + +import com.jkgroller.cryptonote.entity.AccountEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * + */ +@Repository +public interface AccountEntityRepository extends JpaRepository { + + AccountEntity findAccountByUserName(String userName); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/entity/repository/NoteEntityRepository.java b/src/main/java/com/jkgroller/cryptonote/entity/repository/NoteEntityRepository.java new file mode 100644 index 0000000..b2c047e --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/entity/repository/NoteEntityRepository.java @@ -0,0 +1,9 @@ +package com.jkgroller.cryptonote.entity.repository; + +import com.jkgroller.cryptonote.entity.NoteEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface NoteEntityRepository extends JpaRepository { +} diff --git a/src/main/java/com/jkgroller/cryptonote/enums/AccountRole.java b/src/main/java/com/jkgroller/cryptonote/enums/AccountRole.java new file mode 100644 index 0000000..b28c94e --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/enums/AccountRole.java @@ -0,0 +1,9 @@ +package com.jkgroller.cryptonote.enums; + +/** + * + */ +public enum AccountRole { + USER, + ADMIN +} \ No newline at end of file diff --git a/src/main/java/com/jkgroller/cryptonote/resource/Account.java b/src/main/java/com/jkgroller/cryptonote/resource/Account.java new file mode 100644 index 0000000..3c5bd81 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/Account.java @@ -0,0 +1,36 @@ +package com.jkgroller.cryptonote.resource; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.jkgroller.cryptonote.resource.attribute.CredentialsAttribute; +import io.crnk.core.resource.annotations.JsonApiField; +import io.crnk.core.resource.annotations.JsonApiId; + +/** + * Base class for the different types of account resources there may be. Will likely be a resource in the future. + */ +public class Account { + + @JsonApiId + private String identifier; + + @JsonProperty("credentials") + @JsonApiField(readable = true, postable = false, patchable = false, deletable = false) + private CredentialsAttribute credentialsAttribute; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public CredentialsAttribute getCredentialsAttribute() { + return credentialsAttribute; + } + + public void setCredentialsAttribute(CredentialsAttribute credentialsAttribute) { + this.credentialsAttribute = credentialsAttribute; + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/resource/NoteResource.java b/src/main/java/com/jkgroller/cryptonote/resource/NoteResource.java new file mode 100644 index 0000000..099effb --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/NoteResource.java @@ -0,0 +1,83 @@ +package com.jkgroller.cryptonote.resource; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.jkgroller.cryptonote.resource.attribute.CredentialsAttribute; +import io.crnk.core.resource.annotations.JsonApiField; +import io.crnk.core.resource.annotations.JsonApiId; +import io.crnk.core.resource.annotations.JsonApiResource; + +@JsonApiResource(type = "note", resourcePath = "notes") +public class NoteResource { + + @JsonApiId + private String identifier; + + private String name; + + private String contents; + + @JsonProperty("credentials") + @JsonApiField(readable = false, postable = true, patchable = false, deletable = false) + private CredentialsAttribute credentialsAttribute; + + /** + * @return + */ + public String getIdentifier() { + return identifier; + } + + /** + * + * @param identifier + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * + * @return + */ + public String getName() { + return name; + } + + /** + * + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * + * @return + */ + public String getContents() { + return contents; + } + + /** + * @param contents + */ + public void setContents(String contents) { + this.contents = contents; + } + + /** + * @return + */ + public CredentialsAttribute getCredentialsAttribute() { + return credentialsAttribute; + } + + /** + * + * @param credentialsAttribute + */ + public void setCredentialsAttribute(CredentialsAttribute credentialsAttribute) { + this.credentialsAttribute = credentialsAttribute; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/resource/UserAccountResource.java b/src/main/java/com/jkgroller/cryptonote/resource/UserAccountResource.java new file mode 100644 index 0000000..012b4e1 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/UserAccountResource.java @@ -0,0 +1,7 @@ +package com.jkgroller.cryptonote.resource; + +import io.crnk.core.resource.annotations.JsonApiResource; + +@JsonApiResource(type = "userAccount", resourcePath = "userAccounts") +public class UserAccountResource extends Account { +} diff --git a/src/main/java/com/jkgroller/cryptonote/resource/attribute/CredentialsAttribute.java b/src/main/java/com/jkgroller/cryptonote/resource/attribute/CredentialsAttribute.java new file mode 100644 index 0000000..715bcab --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/attribute/CredentialsAttribute.java @@ -0,0 +1,43 @@ +package com.jkgroller.cryptonote.resource.attribute; + +/** + * + */ +public class CredentialsAttribute { + + private String userName; + + private String password; + + /** + * + * @return + */ + public String getUserName() { + return userName; + } + + /** + * + * @param userName + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * + * @return + */ + public String getPassword() { + return password; + } + + /** + * + * @param password + */ + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/resource/repository/NoteResourceRepository.java b/src/main/java/com/jkgroller/cryptonote/resource/repository/NoteResourceRepository.java new file mode 100644 index 0000000..c0cc831 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/repository/NoteResourceRepository.java @@ -0,0 +1,73 @@ +package com.jkgroller.cryptonote.resource.repository; + +import com.jkgroller.cryptonote.converter.NoteResourceConverter; +import com.jkgroller.cryptonote.converter.NoteTOConverter; +import com.jkgroller.cryptonote.resource.NoteResource; +import com.jkgroller.cryptonote.service.NoteService; +import com.jkgroller.cryptonote.service.to.CreateNoteRequestTO; +import com.jkgroller.cryptonote.service.to.CreateNoteResponseTO; +import io.crnk.core.exception.BadRequestException; +import io.crnk.core.queryspec.QuerySpec; +import io.crnk.core.repository.ResourceRepository; +import io.crnk.core.resource.list.ResourceList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collection; + +/** + * + */ +@Component +public class NoteResourceRepository implements ResourceRepository { + + @Autowired + private NoteService noteService; + + @Autowired + private NoteResourceConverter noteResourceConverter; + + @Autowired + private NoteTOConverter noteTOConverter; + + @Override + public Class getResourceClass() { + return NoteResource.class; + } + + @Override + public NoteResource findOne(String s, QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + @Override + public ResourceList findAll(QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + @Override + public ResourceList findAll(Collection collection, QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + @Override + public S save(S s) { + throw new BadRequestException("Unsupported."); + } + + @Override + public S create(S s) { + + CreateNoteRequestTO createNoteRequestTO = noteResourceConverter.noteResourceToCreateEncryptedNoteRequestTO(s); + CreateNoteResponseTO createNoteResponseTO = noteService.createNote(createNoteRequestTO); + + return (S) noteTOConverter.noteTOToNoteResource(createNoteResponseTO.getNoteTO()); + + } + + @Override + public void delete(String s) { + throw new BadRequestException("Unsupported."); + } +} + diff --git a/src/main/java/com/jkgroller/cryptonote/resource/repository/UserAccountResourceRepository.java b/src/main/java/com/jkgroller/cryptonote/resource/repository/UserAccountResourceRepository.java new file mode 100644 index 0000000..688be24 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/resource/repository/UserAccountResourceRepository.java @@ -0,0 +1,103 @@ +package com.jkgroller.cryptonote.resource.repository; + +import com.jkgroller.cryptonote.converter.AccountTOConverter; +import com.jkgroller.cryptonote.resource.UserAccountResource; +import com.jkgroller.cryptonote.service.AccountService; +import com.jkgroller.cryptonote.service.to.CreateNewUserAccountResponseTO; +import io.crnk.core.exception.BadRequestException; +import io.crnk.core.queryspec.QuerySpec; +import io.crnk.core.repository.ResourceRepository; +import io.crnk.core.resource.list.ResourceList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collection; + +/** + * + */ +@Component +public class UserAccountResourceRepository implements ResourceRepository { + + @Autowired + private AccountService accountService; + + @Autowired + private AccountTOConverter accountTOConverter; + + /** + * @return + */ + @Override + public Class getResourceClass() { + return UserAccountResource.class; + } + + /** + * + * @param s + * @param querySpec + * @return + */ + @Override + public UserAccountResource findOne(String s, QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + /** + * + * @param querySpec + * @return + */ + @Override + public ResourceList findAll(QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + /** + * + * @param collection + * @param querySpec + * @return + */ + @Override + public ResourceList findAll(Collection collection, QuerySpec querySpec) { + throw new BadRequestException("Unsupported."); + } + + /** + * + * @param s + * @param + * @return + */ + @Override + public S save(S s) { + throw new BadRequestException("Unsupported."); + } + + /** + * + * @param s + * @param + * @return + */ + @Override + public S create(S s) { + + CreateNewUserAccountResponseTO createNewUserAccountResponseTO = accountService.createNewUserAccount(); + + return (S) accountTOConverter.accountTOToUserAccountResource(createNewUserAccountResponseTO.getAccountTO()); + + } + + /** + * + * @param s + */ + @Override + public void delete(String s) { + throw new BadRequestException("Unsupported."); + } +} + diff --git a/src/main/java/com/jkgroller/cryptonote/service/AccountService.java b/src/main/java/com/jkgroller/cryptonote/service/AccountService.java new file mode 100644 index 0000000..25be757 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/AccountService.java @@ -0,0 +1,22 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.service.to.CreateNewUserAccountResponseTO; +import com.jkgroller.cryptonote.service.to.RetrieveUserAccountRequestTO; +import com.jkgroller.cryptonote.service.to.RetrieveUserAccountResponseTO; + +/** + * + */ +public interface AccountService { + + /** + * @return + */ + CreateNewUserAccountResponseTO createNewUserAccount(); + + /** + * @return + */ + RetrieveUserAccountResponseTO retrieveUserAccount(RetrieveUserAccountRequestTO retrieveUserAccountRequestTO); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/AccountServiceImpl.java b/src/main/java/com/jkgroller/cryptonote/service/AccountServiceImpl.java new file mode 100644 index 0000000..6a4b1a7 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/AccountServiceImpl.java @@ -0,0 +1,138 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.converter.AccountEntityConverter; +import com.jkgroller.cryptonote.entity.AccountEntity; +import com.jkgroller.cryptonote.entity.repository.AccountEntityRepository; +import com.jkgroller.cryptonote.enums.AccountRole; +import com.jkgroller.cryptonote.service.to.*; +import io.crnk.core.exception.UnauthorizedException; +import org.apache.commons.codec.binary.Hex; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.crypto.keygen.BytesKeyGenerator; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * + */ +@Service +public class AccountServiceImpl implements AccountService { + + @Autowired + private AccountEntityConverter accountEntityConverter; + + @Autowired + private AccountEntityRepository accountEntityRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private CipherService cipherService; + + @Autowired + @Qualifier("identifierGenerator") + private BytesKeyGenerator identifierGenerator; + + @Autowired + @Qualifier("encryptionKeyGenerator") + private BytesKeyGenerator encryptionKeyGenerator; + + @Autowired + @Qualifier("userNameGenerator") + private BytesKeyGenerator userNameGenerator; + + @Autowired + @Qualifier("passwordGenerator") + private BytesKeyGenerator passwordGenerator; + + /** + * + * @return + */ + @Override + public CreateNewUserAccountResponseTO createNewUserAccount() { + + String password = generatePassword(); + AccountEntity accountEntity = accountEntityRepository.save(buildAccountEntity(password, AccountRole.USER)); + + CreateNewUserAccountResponseTO createNewUserAccountResponseTO = new CreateNewUserAccountResponseTO(); + createNewUserAccountResponseTO.setAccountTO(accountEntityConverter.accountEntityToAccountTO(accountEntity)); + createNewUserAccountResponseTO.getAccountTO().setPassword(password); + + return createNewUserAccountResponseTO; + + } + + /** + * + * @param retrieveUserAccountRequestTO + * @return + */ + @Override + public RetrieveUserAccountResponseTO retrieveUserAccount(RetrieveUserAccountRequestTO retrieveUserAccountRequestTO) { + + AccountEntity accountEntity = accountEntityRepository.findAccountByUserName(retrieveUserAccountRequestTO.getUserName()); + + if (null != accountEntity && passwordEncoder.matches(retrieveUserAccountRequestTO.getPassword(), accountEntity.getPasswordHash())) { + RetrieveUserAccountResponseTO retrieveUserAccountResponseTO = new RetrieveUserAccountResponseTO(); + AccountTO accountTO = accountEntityConverter.accountEntityToAccountTO(accountEntity); + retrieveUserAccountResponseTO.setAccountTO(accountTO); + return retrieveUserAccountResponseTO; + } + + throw new UnauthorizedException("Unable to verify credentials."); + + } + + /** + * @return + */ + private String generatePassword() { + return Hex.encodeHexString(passwordGenerator.generateKey()); + } + + + /** + * + * @param password + * @return + */ + private AccountEntity buildAccountEntity(String password, AccountRole accountRole) { + + AccountEntity accountEntity = new AccountEntity(); + LocalDateTime localDateTime = LocalDateTime.now(); + + accountEntity.setUserName(Hex.encodeHexString(userNameGenerator.generateKey())); + accountEntity.setPasswordHash(passwordEncoder.encode(password)); + accountEntity.setRole(accountRole.name()); + accountEntity.setIdentifier(Hex.encodeHexString(identifierGenerator.generateKey())); + accountEntity.setCreationDateTime(localDateTime); + accountEntity.setLastLoginDateTime(localDateTime); + + EncryptResponseTO encryptResponseTO = generateEncryptedSurrogateKey(password); + + accountEntity.setEncryptedSurrogateKey(encryptResponseTO.getEncrypted()); + accountEntity.setSurrogateKeySalt(encryptResponseTO.getSalt()); + + return accountEntity; + + } + + /** + * + * @param password + * @return + */ + private EncryptResponseTO generateEncryptedSurrogateKey(String password){ + + EncryptRequestTO encryptRequest = new EncryptRequestTO(password, encryptionKeyGenerator.generateKey()); + + return cipherService.encrypt(encryptRequest); + + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/CipherService.java b/src/main/java/com/jkgroller/cryptonote/service/CipherService.java new file mode 100644 index 0000000..def0e7f --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/CipherService.java @@ -0,0 +1,27 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.service.to.DecryptRequestTO; +import com.jkgroller.cryptonote.service.to.DecryptResponseTO; +import com.jkgroller.cryptonote.service.to.EncryptRequestTO; +import com.jkgroller.cryptonote.service.to.EncryptResponseTO; + +/** + * + */ +public interface CipherService { + + /** + * + * @param encryptRequestTO + * @return + */ + EncryptResponseTO encrypt(EncryptRequestTO encryptRequestTO); + + /** + * + * @param decryptRequestTO + * @return + */ + DecryptResponseTO decrypt(DecryptRequestTO decryptRequestTO); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/CipherServiceImpl.java b/src/main/java/com/jkgroller/cryptonote/service/CipherServiceImpl.java new file mode 100644 index 0000000..1f541ac --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/CipherServiceImpl.java @@ -0,0 +1,70 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.service.to.DecryptRequestTO; +import com.jkgroller.cryptonote.service.to.DecryptResponseTO; +import com.jkgroller.cryptonote.service.to.EncryptRequestTO; +import com.jkgroller.cryptonote.service.to.EncryptResponseTO; +import org.apache.commons.codec.binary.Hex; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.crypto.encrypt.BytesEncryptor; +import org.springframework.security.crypto.encrypt.Encryptors; +import org.springframework.security.crypto.keygen.BytesKeyGenerator; +import org.springframework.security.crypto.keygen.KeyGenerators; +import org.springframework.stereotype.Service; + +/** + * + */ +@Service +public class CipherServiceImpl implements CipherService { + + private final int SALT_SIZE; + + /** + * This is how you inject a value from a properties file into a constant. + */ + public CipherServiceImpl(@Value("${salt.size}") int saltSize) { + this.SALT_SIZE = saltSize; + } + + /** + * + * @param encryptRequestTO + * @return + */ + @Override + public EncryptResponseTO encrypt(EncryptRequestTO encryptRequestTO) { + + BytesKeyGenerator generator = KeyGenerators.secureRandom(SALT_SIZE); + + byte[] saltBytes = generator.generateKey(); + + String saltString = Hex.encodeHexString(saltBytes); + + BytesEncryptor bytesEncryptor = Encryptors.stronger(encryptRequestTO.getKey(), saltString); + + byte[] encrypted = bytesEncryptor.encrypt(encryptRequestTO.getUnencryptedBytes()); + + return new EncryptResponseTO(encrypted, saltBytes); + + } + + /** + * + * @param decryptRequestTO + * @return + */ + @Override + public DecryptResponseTO decrypt(DecryptRequestTO decryptRequestTO) { + + BytesEncryptor bytesEncryptor = Encryptors.stronger(decryptRequestTO.getKey(), + decryptRequestTO.getSaltString()); + + byte[] decrypted = bytesEncryptor.decrypt(decryptRequestTO.getEncrypted()); + + return new DecryptResponseTO(decrypted); + + } + + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/NoteService.java b/src/main/java/com/jkgroller/cryptonote/service/NoteService.java new file mode 100644 index 0000000..1c86156 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/NoteService.java @@ -0,0 +1,13 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.service.to.CreateNoteRequestTO; +import com.jkgroller.cryptonote.service.to.CreateNoteResponseTO; + +/** + * + */ +public interface NoteService { + + CreateNoteResponseTO createNote(CreateNoteRequestTO createNoteRequestTO); + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/NoteServiceImpl.java b/src/main/java/com/jkgroller/cryptonote/service/NoteServiceImpl.java new file mode 100644 index 0000000..a544c80 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/NoteServiceImpl.java @@ -0,0 +1,123 @@ +package com.jkgroller.cryptonote.service; + +import com.jkgroller.cryptonote.converter.NoteEntityConverter; +import com.jkgroller.cryptonote.entity.NoteEntity; +import com.jkgroller.cryptonote.entity.repository.NoteEntityRepository; +import com.jkgroller.cryptonote.service.to.*; +import org.apache.commons.codec.binary.Hex; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.crypto.keygen.BytesKeyGenerator; +import org.springframework.stereotype.Service; + +/** + * + */ +@Service +public class NoteServiceImpl implements NoteService { + + @Autowired + private AccountService accountService; + + @Autowired + private CipherService cipherService; + + @Autowired + private NoteEntityRepository noteEntityRepository; + + @Autowired + private NoteEntityConverter noteEntityConverter; + + @Autowired + @Qualifier("encryptionKeyGenerator") + private BytesKeyGenerator encryptionKeyGenerator; + + @Autowired + @Qualifier("identifierGenerator") + private BytesKeyGenerator identifierGenerator; + + /** + * @param createNoteRequestTO + * @return + */ + @Override + public CreateNoteResponseTO createNote(CreateNoteRequestTO createNoteRequestTO) { + + //Retrieve user account + RetrieveUserAccountRequestTO retrieveUserAccountRequestTO = new RetrieveUserAccountRequestTO(); + + retrieveUserAccountRequestTO.setUserName(createNoteRequestTO.getUserName()); + retrieveUserAccountRequestTO.setPassword(createNoteRequestTO.getPassword()); + + RetrieveUserAccountResponseTO retrieveUserAccountResponseTO = accountService.retrieveUserAccount(retrieveUserAccountRequestTO); + + //Get the entity ready. + NoteEntity noteEntity = new NoteEntity(); + + //Generate encryption Key + byte[] key = encryptionKeyGenerator.generateKey(); + + //Encrypt note name with key + EncryptRequestTO encryptNameRequestTO = new EncryptRequestTO(key, createNoteRequestTO.getNoteName()); + EncryptResponseTO encryptNameResponseTO = cipherService.encrypt(encryptNameRequestTO); + + //Encrypt note contents with key. + EncryptRequestTO encryptContentsRequestTO = new EncryptRequestTO(key, createNoteRequestTO.getNoteContents()); + EncryptResponseTO encryptContentsResponseTO = cipherService.encrypt(encryptContentsRequestTO); + + //Decrypt surrogate key. + DecryptRequestTO decryptSurrogateKeyRequestTO = new DecryptRequestTO(createNoteRequestTO.getPassword() + , retrieveUserAccountResponseTO.getAccountTO().getEncryptedSurrogateKey() + , retrieveUserAccountResponseTO.getAccountTO().getSurrogateKeySalt()); + + DecryptResponseTO decryptSurrogateKeyResponseTO = cipherService.decrypt(decryptSurrogateKeyRequestTO); + + //Encrypt the key. + EncryptRequestTO encryptKeyRequestTO = new EncryptRequestTO(decryptSurrogateKeyResponseTO.getUnencrypted(), key); + EncryptResponseTO encryptKeyResponseTO = cipherService.encrypt(encryptKeyRequestTO); + + //Generate an identifier. + String noteIdentifier = Hex.encodeHexString(identifierGenerator.generateKey()); + + //Save it. + noteEntity.setIdentifier(noteIdentifier); + noteEntity.setContents(encryptContentsResponseTO.getEncrypted()); + noteEntity.setContentsSalt(encryptContentsResponseTO.getSalt()); + noteEntity.setName(encryptNameResponseTO.getEncrypted()); + noteEntity.setNameSalt(encryptNameResponseTO.getSalt()); + noteEntity.setKey(encryptKeyResponseTO.getEncrypted()); + noteEntity.setKeySalt(encryptKeyResponseTO.getSalt()); + + noteEntity = noteEntityRepository.save(noteEntity); + + NoteTO noteTO = decryptNote(noteEntity, key); + + CreateNoteResponseTO createNoteResponseTO = new CreateNoteResponseTO(); + createNoteResponseTO.setNoteTO(noteTO); + + return createNoteResponseTO; + } + + private NoteTO decryptNote(NoteEntity noteEntity, byte[] key) { + + NoteTO noteTO = new NoteTO(); + + DecryptRequestTO decryptNoteContentsRequestTO = new DecryptRequestTO(Hex.encodeHexString(key) + , noteEntity.getContents() + , noteEntity.getContentsSalt()); + + DecryptRequestTO decryptNoteNameRequestTO = new DecryptRequestTO(Hex.encodeHexString(key) + , noteEntity.getContents() + , noteEntity.getContentsSalt()); + + noteTO.setContents(cipherService.decrypt(decryptNoteContentsRequestTO).getUnencrypted()); + + noteTO.setName(cipherService.decrypt(decryptNoteNameRequestTO).getUnencrypted()); + + noteTO.setIdentifier(noteEntity.getIdentifier()); + + return noteTO; + + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/AccountTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/AccountTO.java new file mode 100644 index 0000000..0a497f5 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/AccountTO.java @@ -0,0 +1,78 @@ +package com.jkgroller.cryptonote.service.to; + +import com.jkgroller.cryptonote.enums.AccountRole; + +import java.time.LocalDateTime; + +public class AccountTO { + + private String identifier; + + private String userName; + + private String password; + + private AccountRole role; + + private LocalDateTime creationDateTime; + + private byte[] encryptedSurrogateKey; + + private byte[] surrogateKeySalt; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public AccountRole getRole() { + return role; + } + + public void setRole(AccountRole role) { + this.role = role; + } + + public LocalDateTime getCreationDateTime() { + return creationDateTime; + } + + public void setCreationDateTime(LocalDateTime creationDateTime) { + this.creationDateTime = creationDateTime; + } + + public byte[] getEncryptedSurrogateKey() { + return encryptedSurrogateKey; + } + + public void setEncryptedSurrogateKey(byte[] encryptedSurrogateKey) { + this.encryptedSurrogateKey = encryptedSurrogateKey; + } + + public byte[] getSurrogateKeySalt() { + return surrogateKeySalt; + } + + public void setSurrogateKeySalt(byte[] surrogateKeySalt) { + this.surrogateKeySalt = surrogateKeySalt; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewAccountResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewAccountResponseTO.java new file mode 100644 index 0000000..4708e2a --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewAccountResponseTO.java @@ -0,0 +1,18 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class CreateNewAccountResponseTO { + + private AccountTO accountTO; + + public AccountTO getAccountTO() { + return accountTO; + } + + public void setAccountTO(AccountTO accountTO) { + this.accountTO = accountTO; + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewUserAccountResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewUserAccountResponseTO.java new file mode 100644 index 0000000..3abbd7d --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNewUserAccountResponseTO.java @@ -0,0 +1,19 @@ +package com.jkgroller.cryptonote.service.to; + +import com.jkgroller.cryptonote.enums.AccountRole; + +/** + * + */ +public class CreateNewUserAccountResponseTO extends CreateNewAccountResponseTO { + + /** + * + */ + public CreateNewUserAccountResponseTO() { + AccountTO accountTO = new AccountTO(); + accountTO.setRole(AccountRole.USER); + super.setAccountTO(accountTO); + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteRequestTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteRequestTO.java new file mode 100644 index 0000000..8183e43 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteRequestTO.java @@ -0,0 +1,78 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class CreateNoteRequestTO { + + private String userName; + + private String password; + + private String noteName; + + private String noteContents; + + /** + * @return + */ + public String getUserName() { + return userName; + } + + /** + * + * @param userName + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * + * @return + */ + public String getPassword() { + return password; + } + + /** + * + * @param password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * + * @return + */ + public String getNoteName() { + return noteName; + } + + /** + * + * @param noteName + */ + public void setNoteName(String noteName) { + this.noteName = noteName; + } + + /** + * + * @return + */ + public String getNoteContents() { + return noteContents; + } + + /** + * + * @param noteContents + */ + public void setNoteContents(String noteContents) { + this.noteContents = noteContents; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteResponseTO.java new file mode 100644 index 0000000..487fe01 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/CreateNoteResponseTO.java @@ -0,0 +1,23 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class CreateNoteResponseTO { + + private NoteTO noteTO; + + /** + * @return + */ + public NoteTO getNoteTO() { + return noteTO; + } + + /** + * @param noteTO + */ + public void setNoteTO(NoteTO noteTO) { + this.noteTO = noteTO; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/DecryptRequestTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/DecryptRequestTO.java new file mode 100644 index 0000000..a5970e4 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/DecryptRequestTO.java @@ -0,0 +1,60 @@ +package com.jkgroller.cryptonote.service.to; + +import org.apache.commons.codec.binary.Hex; + +/** + * + */ +public class DecryptRequestTO { + + private final String key; + + private final byte[] encrypted; + + private final byte[] salt; + + /** + * + * @param key + * @param encrypted + * @param salt + */ + public DecryptRequestTO(String key, byte[] encrypted, byte[] salt) { + super(); + this.key = key; + this.encrypted = encrypted; + this.salt = salt; + } + + /** + * + * @return + */ + public String getKey() { + return key; + } + + /** + * + * @return + */ + public byte[] getEncrypted() { + return encrypted; + } + + /** + * @return the salt + */ + public byte[] getSalt() { + return salt; + } + + /** + * @return the salt + */ + public String getSaltString() { + return Hex.encodeHexString(salt); + } + + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/DecryptResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/DecryptResponseTO.java new file mode 100644 index 0000000..5f8880c --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/DecryptResponseTO.java @@ -0,0 +1,35 @@ +package com.jkgroller.cryptonote.service.to; + +import java.nio.charset.StandardCharsets; + +/** + * + */ +public class DecryptResponseTO { + + private final String unencrypted; + + /** + * @param unencrypted + */ + public DecryptResponseTO(String unencrypted) { + super(); + this.unencrypted = unencrypted; + } + + /** + * @param unencrypted + */ + public DecryptResponseTO(byte[] unencrypted) { + super(); + this.unencrypted = new String(unencrypted, StandardCharsets.UTF_8); + } + + /** + * @return the unencrypted + */ + public String getUnencrypted() { + return unencrypted; + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/EncryptRequestTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/EncryptRequestTO.java new file mode 100644 index 0000000..957347a --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/EncryptRequestTO.java @@ -0,0 +1,79 @@ +package com.jkgroller.cryptonote.service.to; + +import org.apache.commons.codec.binary.Hex; + +import java.nio.charset.StandardCharsets; + +/** + * + */ +public class EncryptRequestTO { + + private final String key; + + private final String unencrypted; + + /** + * @param key + * @param unencrypted + */ + public EncryptRequestTO(String key, String unencrypted) { + super(); + this.key = key; + this.unencrypted = unencrypted; + } + + /** + * @param key + * @param unencrypted + */ + public EncryptRequestTO(String key, byte[] unencrypted) { + super(); + this.key = key; + this.unencrypted = Hex.encodeHexString(unencrypted); + } + + /** + * + * @param key + * @param unencrypted + */ + public EncryptRequestTO(byte[] key, byte[] unencrypted) { + super(); + this.key = Hex.encodeHexString(key); + this.unencrypted = Hex.encodeHexString(unencrypted); + } + + /** + * + * @param key + * @param unencrypted + */ + public EncryptRequestTO(byte[] key, String unencrypted) { + super(); + this.key = Hex.encodeHexString(key); + this.unencrypted = unencrypted; + } + + /** + * @return + */ + public String getKey() { + return key; + } + + /** + * @return + */ + public String getUnencrypted() { + return unencrypted; + } + + /** + * @return + */ + public byte[] getUnencryptedBytes() { + return unencrypted.getBytes(StandardCharsets.UTF_8); + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/EncryptResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/EncryptResponseTO.java new file mode 100644 index 0000000..d2c99af --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/EncryptResponseTO.java @@ -0,0 +1,44 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class EncryptResponseTO { + + private final byte[] encrypted; + + private final byte[] salt; + + /** + * @param encrypted + * @param salt + */ + public EncryptResponseTO(byte[] encrypted, byte[] salt) { + this.encrypted = encrypted; + this.salt = salt; + } + + /** + * + */ + public EncryptResponseTO() { + this.encrypted = null; + this.salt = null; + } + + /** + * @return the encrypted + */ + public byte[] getEncrypted() { + return encrypted; + } + + /** + * + * @return + */ + public byte[] getSalt() { + return salt; + } + +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/NoteTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/NoteTO.java new file mode 100644 index 0000000..eff5a87 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/NoteTO.java @@ -0,0 +1,55 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class NoteTO { + + private String identifier; + + private String name; + + private String contents; + + /** + * @return + */ + public String getIdentifier() { + return identifier; + } + + /** + * @param identifier + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * @return + */ + public String getName() { + return name; + } + + /** + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return + */ + public String getContents() { + return contents; + } + + /** + * @param contents + */ + public void setContents(String contents) { + this.contents = contents; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountRequestTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountRequestTO.java new file mode 100644 index 0000000..b39a032 --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountRequestTO.java @@ -0,0 +1,39 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class RetrieveUserAccountRequestTO { + + private String userName; + + private String password; + + /** + * @return + */ + public String getUserName() { + return userName; + } + + /** + * @param userName + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * @return + */ + public String getPassword() { + return password; + } + + /** + * @param password + */ + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountResponseTO.java b/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountResponseTO.java new file mode 100644 index 0000000..487f32a --- /dev/null +++ b/src/main/java/com/jkgroller/cryptonote/service/to/RetrieveUserAccountResponseTO.java @@ -0,0 +1,19 @@ +package com.jkgroller.cryptonote.service.to; + +/** + * + */ +public class RetrieveUserAccountResponseTO { + + private AccountTO accountTO; + + public AccountTO getAccountTO() { + return accountTO; + } + + public void setAccountTO(AccountTO accountTO) { + this.accountTO = accountTO; + } + + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..186d05c --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,30 @@ +#=============================== +# = CRNK +# =============================== +crnk.path-prefix=/v1 +crnk.return404-on-null=true + +#=============================== +# = Security & Generators +# =============================== +password.encryption.strength=12 +salt.size=32 +encryption.key.length=32 +username.length=8 +password.length=16 +identifier.length=8 + +#=============================== +# = Data Source +# =============================== +spring.datasource.url=jdbc:h2:mem:cryptonote;DB_CLOSE_DELAY=-1 +spring.datasource.platform=h2 +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.show-sql=false +#spring.datasource.initialization-mode=ALWAYS +#spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect +spring.h2.console.enabled=true +spring.h2.console.path=/h2 +spring.h2.console.settings.web-allow-others=true diff --git a/src/test/resources/db.sql b/src/test/resources/db.sql new file mode 100644 index 0000000..a2b3dbc --- /dev/null +++ b/src/test/resources/db.sql @@ -0,0 +1,58 @@ +-- -------------------------------------------------------- +-- Host: 192.168.0.18 +-- Server version: 5.7.18-0ubuntu0.16.04.1 - (Ubuntu) +-- Server OS: Linux +-- HeidiSQL Version: 9.4.0.5169 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + + +-- Dumping database structure for spring_security +CREATE DATABASE IF NOT EXISTS `spring_security` /*!40100 DEFAULT CHARACTER SET latin1 */; +USE `spring_security`; + +-- Dumping structure for table spring_security.member +CREATE TABLE IF NOT EXISTS `member` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `active` int(1) NOT NULL, + `verified` int(1) NOT NULL, + `email` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `surrogate_key` binary(58) NOT NULL, + `surrogate_key_salt` binary(28) NOT NULL, + `verification_key` char(36) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8; + +-- Data exporting was unselected. +-- Dumping structure for table spring_security.member_role +CREATE TABLE IF NOT EXISTS `member_role` ( + `member_id` int(11) NOT NULL, + `role_id` int(11) NOT NULL, + PRIMARY KEY (`member_id`,`role_id`), + KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`), + CONSTRAINT `FK34g7epqlcxqloewku3aoqhhmg` FOREIGN KEY (`member_id`) REFERENCES `member` (`id`), + CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`member_id`) REFERENCES `member` (`id`), + CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`), + CONSTRAINT `FKdiix07v86r3ntrbs3l02qr7y0` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Data exporting was unselected. +-- Dumping structure for table spring_security.role +CREATE TABLE IF NOT EXISTS `role` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; + +-- Data exporting was unselected. +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;