logo
TrungTQ

Symmetric Encryption and Asymmetric Encryption: Security Solutions for Distributed Systems

  • Author: Administrator
  • Published On: 15 Jul 2025

Symmetric Encryption and Asymmetric Encryption: Security Solutions for Distributed Systems

In the modern digital world, information security is a vital factor, especially in distributed systems and microservices architectures. Encryption plays a key role in protecting data from unauthorized access. This article will delve into two basic types of encryption: Symmetric Encryption and Asymmetric Encryption, and discuss their practical applications, especially in authentication and authorization using JSON Web Tokens (JWT).

1.Symmetric Encryption

Symmetric encryption uses the same secret key to encrypt and decrypt data. This means that both the sender and the receiver must know the secret key.

1.1 Advantages:

  • Speed: Encryption and decryption are very fast, suitable for encrypting large amounts of data.
  • Efficiency: Consumes less computational resources than asymmetric cryptography.

1.2 Disadvantages:

  • Key Management: Distributing and protecting secret keys is a major challenge, especially in a distributed environment. If a key is compromised, all data encrypted with that key is compromised.
  • Scalability: Difficulty in managing many different secret keys for many different entities.

1.3 Popular symmetric encryption algorithms:

  • AES (Advanced Encryption Standard): Widely used encryption standard, replacing DES (Data Encryption Standard).
  • DES (Data Encryption Standard): Older algorithm, less used today due to short key length, vulnerable to brute-force attacks.
  • 3DES (Triple DES): An improvement of DES, using three DES keys for increased security.

1.4 Practical application:

  • Encrypt data on hard drive.
  • Encrypt data in the database.
  • Encrypt the session between client and server.

2. Asymmetric Encryption

Asymmetric encryption uses a pair of keys: a public key and a private key. The public key is widely shared, while the private key must be kept absolutely secret. Data encrypted with a public key can only be decrypted with the corresponding private key, and vice versa.

2.1 Advantages:

  • Key Management: Distributing public keys is much easier than distributing private keys.
  • Authentication: Allows authentication of the origin of data through digital signatures.

2.2 Disadvantages:

  • Speed: Encryption and decryption are much slower than symmetric encryption.
  • Efficiency: Consumes more computational resources.

2.3 Popular asymmetric encryption algorithms:

  • RSA (Rivest-Shamir-Adleman): Popular algorithm for encryption and digital signatures.
  • ECC (Elliptic Curve Cryptography): An algorithm that uses elliptic curves, providing the same level of security as RSA but with shorter key lengths.
  • DSA (Digital Signature Algorithm): Specialized algorithm for digital signatures.

2.4 Practical application:

  • Digital Signature: Authenticates the integrity and origin of a document.
  • Email encryption: Protect email content from being read by unauthorized people.
  • HTTPS Protocol: Secures communication between browser and web server.

3. Comparison of symmetric and asymmetric encryption

Below is a summary comparison table between symmetric and asymmetric encryption:

Characteristic Symmetric encryption Asymmetric encryption
Lock A secret key Two keys (public key and private key)
Speed Fast Slow
Effective Resource efficiency Resource intensive
Key Management Hard Easier
Application Encrypt large amounts of data Authentication, electronic signature

4. JSON Web Tokens (JWT) and the application of encryption

JWT is an open standard for securely transmitting data between parties as JSON objects. JWTs are commonly used for authentication and authorization in web applications and APIs. Encryption plays an important role in ensuring the integrity and authentication of JWTs.

The structure of a JWT consists of three parts:

  1. Header: Contains information about the encryption algorithm used (e.g. HS256, RS256).
  2. Payload: Contains information (claims) about the user or application.
  3. Signature: Created by encrypting the header and payload with a public key (in case of HS256) or a secret key (in case of RS256).

4.1 HS256 (HMAC-SHA256) - Symmetric encryption

HS256 uses the HMAC-SHA256 algorithm and a secret key to generate the signature for the JWT. The server uses the same secret key to verify the integrity of the JWT.

Advantage:

  • Fast speed.
  • Easy to deploy.

Disadvantages:

  • The secret key must be shared between the issuing server and the authentication server, increasing the risk of key disclosure.
  • Not suitable for complex distributed systems where many services need JWT authentication.

4.2 RS256 (RSA Signature with SHA-256) - Asymmetric encryption

RS256 uses the RSA algorithm and a public/private key pair. The server issuing the JWT uses the private key to generate the signature. Other services use the public key to verify the signature.

Advantage:

  • Higher security because the secret key does not need to be shared.
  • Suitable for distributed systems where multiple services need JWT authentication.

Disadvantages:

  • Slower speed than HS256.
  • More complex implementation.

4.3 Illustration of JWT authentication process with RS256

JWT authentication process with RS256 :

  1. The issuing server uses the secret key to generate the JWT.
  2. JWT is sent to the client.
  3. Client sends JWT to authentication server.
  4. The authentication server uses the public key to verify the signature of the JWT.
  5. If the signature is valid, the authentication server believes the JWT is valid and allows access to the resource.

5. Example of Spring Security configuration with JWT

Spring Security is a powerful framework for securing Java applications. Here is a simple example of how to configure Spring Security for authentication and authorization using JWT.

5.1 Add necessary dependencies

 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> 5.2 SecurityFilterChain Configuration <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>

 @Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { private final AuthTokenFilter authTokenFilter; public SecurityConfig(AuthTokenFilter authTokenFilter) { this.authTokenFilter = authTokenFilter; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() // Cho phép truy cập không cần xác thực .anyRequest().authenticated() // Yêu cầu xác thực cho tất cả các request khác ) .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class); // Thêm filter để xác thực JWT return http.build(); } } Explain: @Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { private final AuthTokenFilter authTokenFilter; public SecurityConfig(AuthTokenFilter authTokenFilter) { this.authTokenFilter = authTokenFilter; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() // Cho phép truy cập không cần xác thực .anyRequest().authenticated() // Yêu cầu xác thực cho tất cả các request khác ) .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class); // Thêm filter để xác thực JWT return http.build(); } }

  • @EnableWebSecurity: Enable Spring Security.
  • @EnableMethodSecurity: Allows the use of annotations to control access.
  • SecurityFilterChain: Defines a chain of filters to handle requests.
  • csrf().disable(): Turn off CSRF protection for stateless authentication (JWT).
  • sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS): Set session creation policy to STATELESS, because JWT is stateless.
  • authorizeHttpRequests(): Configures requests to be authorized.
  • addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class): Add AuthTokenFilter before UsernamePasswordAuthenticationFilter to validate JWT before authenticating with username/password.

5.3 Building AuthTokenFilter

 @Component public class AuthTokenFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; private final UserDetailsService userDetailsService; public AuthTokenFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) { this.jwtUtil = jwtUtil; this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { String jwt = jwtUtil.parseJwt(request); if (jwt != null && jwtUtil.validateJwtToken(jwt)) { String username = jwtUtil.getUserNameFromJwtToken(jwt); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception e) { logger.error("Cannot set user authentication: {}", e); } filterChain.doFilter(request, response); } } Explain: @Component public class AuthTokenFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; private final UserDetailsService userDetailsService; public AuthTokenFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) { this.jwtUtil = jwtUtil; this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { String jwt = jwtUtil.parseJwt(request); if (jwt != null && jwtUtil.validateJwtToken(jwt)) { String username = jwtUtil.getUserNameFromJwtToken(jwt); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception e) { logger.error("Cannot set user authentication: {}", e); } filterChain.doFilter(request, response); } }

  • OncePerRequestFilter: This filter is only executed once per request.
  • jwtUtil.parseJwt(request): Get JWT from request.
  • jwtUtil.validateJwtToken(jwt): Check the validity of a JWT.
  • jwtUtil.getUserNameFromJwtToken(jwt): Get username from JWT.
  • userDetailsService.loadUserByUsername(username): Get user information from database.
  • UsernamePasswordAuthenticationToken: Creates an authentication object to save to SecurityContextHolder.

5.4 Building JwtUtil class

 @Component public class JwtUtil { @Value("${jwt.secret}") private String jwtSecret; @Value("${jwt.expirationMs}") private int jwtExpirationMs; public String generateJwtToken(Authentication authentication) { UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); return Jwts.builder() .setSubject((userPrincipal.getUsername())) .setIssuedAt(new Date()) .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) .signWith(key(), SignatureAlgorithm.HS256) .compact(); } private Key key() { return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); } public String getUserNameFromJwtToken(String token) { return Jwts.parserBuilder().setSigningKey(key()).build() .parseClaimsJws(token).getBody().getSubject(); } public boolean validateJwtToken(String token) { try { Jwts.parserBuilder().setSigningKey(key()).build().parseClaimsJws(token); return true; } catch (MalformedJwtException e) { logger.error("Invalid JWT token: {}", e.getMessage()); } catch (ExpiredJwtException e) { logger.error("JWT token is expired: {}", e.getMessage()); } catch (UnsupportedJwtException e) { logger.error("JWT token is unsupported: {}", e.getMessage()); } catch (IllegalArgumentException e) { logger.error("JWT claims string is empty: {}", e.getMessage()); } return false; } public String parseJwt(HttpServletRequest request) { String headerAuth = request.getHeader("Authorization"); if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { return headerAuth.substring(7, headerAuth.length()); } return null; } } Explain: @Component public class JwtUtil { @Value("${jwt.secret}") private String jwtSecret; @Value("${jwt.expirationMs}") private int jwtExpirationMs; public String generateJwtToken(Authentication authentication) { UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); return Jwts.builder() .setSubject((userPrincipal.getUsername())) .setIssuedAt(new Date()) .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) .signWith(key(), SignatureAlgorithm.HS256) .compact(); } private Key key() { return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); } public String getUserNameFromJwtToken(String token) { return Jwts.parserBuilder().setSigningKey(key()).build() .parseClaimsJws(token).getBody().getSubject(); } public boolean validateJwtToken(String token) { try { Jwts.parserBuilder().setSigningKey(key()).build().parseClaimsJws(token); return true; } catch (MalformedJwtException e) { logger.error("Invalid JWT token: {}", e.getMessage()); } catch (ExpiredJwtException e) { logger.error("JWT token is expired: {}", e.getMessage()); } catch (UnsupportedJwtException e) { logger.error("JWT token is unsupported: {}", e.getMessage()); } catch (IllegalArgumentException e) { logger.error("JWT claims string is empty: {}", e.getMessage()); } return false; } public String parseJwt(HttpServletRequest request) { String headerAuth = request.getHeader("Authorization"); if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { return headerAuth.substring(7, headerAuth.length()); } return null; } }

  • @Value("${jwt.secret}"): Get the secret key value from the configuration file.
  • @Value("${jwt.expirationMs}"): Get the JWT expiration time from the configuration file.
  • generateJwtToken(Authentication authentication): Generates a JWT from authentication information.
  • getUserNameFromJwtToken(String token): Get username from JWT.
  • validateJwtToken(String token): Checks the validity of a JWT.
  • parseJwt(HttpServletRequest request): Get the JWT from the request's Authorization header.

6. Private key security and public key verification

In the process of using encryption, protecting the secret key and verifying the public key are extremely important.

6.1 Secret key security

The secret key needs to be stored securely to avoid disclosure to unauthorized persons. Some methods of securing the secret key:

  • Secret key encryption: Use another key to encrypt the secret key.
  • Using Hardware Security Module (HSM): HSM is a dedicated hardware device for storing and managing keys.
  • Access Management: Grant access to secret keys only to the people or applications that need them.

6.2 Public Key Verification

Before using a public key to verify a signature, you need to make sure that the public key is correct and belongs to a person or organization you trust. Some methods of verifying public keys:

  • Using Certificate Authority (CA): A CA is a trusted organization responsible for verifying the identity of the person or organization that owns a public key and issuing digital certificates.
  • Web of Trust: A distributed model in which individuals verify each other's public keys.
  • Manual verification: Compare the public key with a previously verified copy.

7. Applications in Microservices architecture

In microservices architecture, authentication and authorization are extremely important. JWT and asymmetric encryption (RS256) are a popular solution to solve this problem.

For example:

  • API Gateway: API Gateway can authenticate JWT and route requests to appropriate microservices.
  • Service-to-service authentication: Microservices can use JWT to authenticate each other.

Read more about Authentication and authorization in microservices architecture .

8. Token Expiration

Token expiration is an important factor in security. Tokens should have a short expiration time to minimize the risk in case the token is stolen. However, an expiration time that is too short can be inconvenient for users, as they have to log in again frequently.

A common solution is to use a refresh token. Refresh tokens have a longer expiration time and are used to request a new access token when the access token expires.

9. Conclusion

Symmetric and asymmetric encryption are two important tools in information security. Choosing the right encryption type depends on the specific requirements of the application. In distributed systems and microservices architectures, asymmetric encryption (RS256) and JWT are a popular solution for authentication and authorization.

Hopefully this article has given you an overview of symmetric and asymmetric encryption and their applications in practice.

  • Share On: