View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    *
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   *******************************************************************************/
11  package com.jsql.view.swing.manager.util;
12  
13  import com.jsql.util.I18nUtil;
14  import com.jsql.util.LogLevelUtil;
15  import com.jsql.util.ThreadUtil;
16  import com.jsql.util.bruter.Bruter;
17  import com.jsql.util.bruter.HashBruter;
18  import com.jsql.view.swing.manager.ManagerBruteForce;
19  import com.jsql.view.swing.util.I18nViewUtil;
20  import org.apache.commons.lang3.StringUtils;
21  import org.apache.logging.log4j.LogManager;
22  import org.apache.logging.log4j.Logger;
23  
24  import javax.swing.*;
25  import javax.swing.text.BadLocationException;
26  import java.awt.event.ActionEvent;
27  import java.awt.event.ActionListener;
28  import java.util.Locale;
29  
30  /**
31   * Run a brute force attack.
32   */
33  public class ActionBruteForce implements ActionListener, Runnable {
34      
35      private static final Logger LOGGER = LogManager.getRootLogger();
36  
37      private final ManagerBruteForce bruteForceManager;
38      
39      private boolean isStopped = false;
40      
41      public ActionBruteForce(ManagerBruteForce bruteForceManager) {
42          this.bruteForceManager = bruteForceManager;
43      }
44  
45      @Override
46      public void actionPerformed(ActionEvent actionEvent) {
47          if (this.bruteForceManager.getRun().getState() == StateButton.STOPPABLE) {
48              this.bruteForceManager.getRun().setEnabled(false);
49              this.isStopped = true;
50          } else {
51              if (StringUtils.isEmpty(this.bruteForceManager.getHash().getText())) {
52                  LOGGER.log(LogLevelUtil.CONSOLE_ERROR, () -> I18nUtil.valueByKey("BRUTEFORCE_EMPTY_HASH"));
53                  return;
54              } else if (this.isRangeNotSelected()) {
55                  LOGGER.log(LogLevelUtil.CONSOLE_ERROR, () -> I18nUtil.valueByKey("BRUTEFORCE_CHARACTER_RANGE"));
56                  return;
57              } else if (this.isLengthNotValid()) {
58                  LOGGER.log(LogLevelUtil.CONSOLE_ERROR, () -> I18nUtil.valueByKey("BRUTEFORCE_INCORRECT_MIN_MAX_LENGTH"));
59                  return;
60              }
61              new Thread(this, "ThreadDisplayBruteForce").start();
62          }
63      }
64  
65      private boolean isLengthNotValid() {
66          return Integer.parseInt(this.bruteForceManager.getMaximumLength().getValue().toString())
67              < Integer.parseInt(this.bruteForceManager.getMinimumLength().getValue().toString());
68      }
69  
70      private boolean isRangeNotSelected() {
71          return !this.bruteForceManager.getSpecialCharacters().isSelected()
72              && !this.bruteForceManager.getUpperCaseCharacters().isSelected()
73              && !this.bruteForceManager.getLowerCaseCharacters().isSelected()
74              && !this.bruteForceManager.getNumericCharacters().isSelected();
75      }
76  
77      @Override
78      public void run() {
79          // Reset the panel
80          this.bruteForceManager.getRun().setText(I18nViewUtil.valueByKey("BRUTEFORCE_STOP"));
81          this.bruteForceManager.getRun().setState(StateButton.STOPPABLE);
82          this.bruteForceManager.showLoader(true);
83          this.bruteForceManager.getResult().setText(null);
84  
85          final var hashBruter = new HashBruter();
86          this.initBruter(hashBruter);
87  
88          // Begin the reverse hashing process
89          new Thread(hashBruter::tryBruteForce, "ThreadRunBruteForce").start();
90          while (!hashBruter.isDone() && !hashBruter.isFound() && !this.isStopped) {
91              
92              hashBruter.setEndtime(System.nanoTime());
93              ThreadUtil.sleep(1000);  // delay to update result panel
94              
95              int selectionStart = this.bruteForceManager.getResult().getSelectionStart();
96              int selectionEnd = this.bruteForceManager.getResult().getSelectionEnd();
97              
98              this.updateResult(hashBruter);
99  
100             this.bruteForceManager.getResult().setSelectionStart(selectionStart);
101             this.bruteForceManager.getResult().setSelectionEnd(selectionEnd);
102             
103             if (this.isStopped) {
104                 hashBruter.setIsDone(true);
105                 hashBruter.setFound(true);
106                 break;
107             }
108         }
109 
110         this.displayResult(hashBruter);
111 
112         this.isStopped = false;
113         this.bruteForceManager.showLoader(false);
114         this.bruteForceManager.getRun().setText(I18nViewUtil.valueByKey("BRUTEFORCE_RUN_BUTTON_LABEL"));
115         this.bruteForceManager.getRun().setEnabled(true);
116         this.bruteForceManager.getRun().setState(StateButton.STARTABLE);
117     }
118 
119     private void updateResult(final HashBruter hashBruter) {
120         this.bruteForceManager.getResult().setText(I18nUtil.valueByKey("BRUTEFORCE_CURRENT_STRING") + ": " + hashBruter.getPassword());
121         this.append(I18nUtil.valueByKey("BRUTEFORCE_CURRENT_HASH") + ": " + hashBruter.getGeneratedHash() + "\n");
122         this.append(I18nUtil.valueByKey("BRUTEFORCE_POSSIBILITIES") + ": " + hashBruter.getNumberOfPossibilities());
123         this.append(I18nUtil.valueByKey("BRUTEFORCE_CHECKED_HASHES") + ": " + hashBruter.getCounter());
124         this.append(I18nUtil.valueByKey("BRUTEFORCE_ESTIMATED") + ": " + hashBruter.getRemainder());
125         this.append(I18nUtil.valueByKey("BRUTEFORCE_PERSECOND") + ": " + hashBruter.getPerSecond() + "\n");
126         this.append(hashBruter.calculateTimeElapsed());
127 
128         if (hashBruter.getPerSecond() != 0) {
129             float remainingDuration = Float.parseFloat(Long.toString(hashBruter.getRemainder())) / hashBruter.getPerSecond();
130             this.append(String.format(
131                 Bruter.PATTERN_PERIOD,
132                 I18nUtil.valueByKey("BRUTEFORCE_TRAVERSING_REMAINING"),
133                 Math.round(Math.floor(remainingDuration / 60f / 60.0f / 24f)), I18nUtil.valueByKey("BRUTEFORCE_DAYS"),
134                 Math.round(Math.floor(remainingDuration / 60f / 60f % 24)), I18nUtil.valueByKey("BRUTEFORCE_HOURS"),
135                 Math.round(Math.floor(remainingDuration / 60f % 60)), I18nUtil.valueByKey("BRUTEFORCE_MINUTES"),
136                 Math.round(remainingDuration % 60), I18nUtil.valueByKey("BRUTEFORCE_SECONDS")
137             ));
138         }
139 
140         this.append(String.format(
141             "%s: %s%%",
142             I18nUtil.valueByKey("BRUTEFORCE_PERCENT_DONE"),
143             100 * (float) hashBruter.getCounter() / hashBruter.getNumberOfPossibilities()
144         ));
145     }
146 
147     private void initBruter(final HashBruter hashBruter) {
148         hashBruter.setMinLength(Integer.parseInt(this.bruteForceManager.getMinimumLength().getValue().toString()));
149         hashBruter.setMaxLength(Integer.parseInt(this.bruteForceManager.getMaximumLength().getValue().toString()));
150 
151         if (this.bruteForceManager.getSpecialCharacters().isSelected()) {
152             hashBruter.addSpecialCharacters();
153         }
154         if (this.bruteForceManager.getUpperCaseCharacters().isSelected()) {
155             hashBruter.addUpperCaseLetters();
156         }
157         if (this.bruteForceManager.getLowerCaseCharacters().isSelected()) {
158             hashBruter.addLowerCaseLetters();
159         }
160         if (this.bruteForceManager.getNumericCharacters().isSelected()) {
161             hashBruter.addDigits();
162         }
163         if (StringUtils.isNotEmpty(this.bruteForceManager.getExclude().getText())) {
164             hashBruter.excludeChars(this.bruteForceManager.getExclude().getText());
165         }
166 
167         hashBruter.setType((String) this.bruteForceManager.getHashTypes().getSelectedItem());
168         hashBruter.setHash(
169             this.bruteForceManager.getHash().getText()
170             .toUpperCase(Locale.ROOT)
171             .replaceAll("[^a-zA-Z0-9]", StringUtils.EMPTY)
172             .trim()
173         );
174     }
175 
176     private void displayResult(final HashBruter hashBruter) {
177         // Display the result
178         if (this.isStopped) {
179             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, () -> I18nUtil.valueByKey("BRUTEFORCE_ABORTED"));
180         } else if (hashBruter.isFound()) {
181             this.append(String.format(
182                 "%n%s:%n%s => %s",
183                 I18nUtil.valueByKey("BRUTEFORCE_FOUND_HASH"),
184                 hashBruter.getGeneratedHash(),
185                 hashBruter.getPassword()
186             ));
187             LOGGER.log(
188                 LogLevelUtil.CONSOLE_SUCCESS,
189                 "{}: {} => {}",
190                 () -> I18nUtil.valueByKey("BRUTEFORCE_FOUND_HASH"),
191                 hashBruter::getGeneratedHash,
192                 hashBruter::getPassword
193             );
194         } else if (hashBruter.isDone()) {
195             this.append("\n"+ I18nUtil.valueByKey("BRUTEFORCE_HASH_NOT_FOUND"));
196             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, () -> I18nUtil.valueByKey("BRUTEFORCE_HASH_NOT_FOUND"));
197         }
198     }
199 
200     private void append(String text) {
201         try {
202             JTextPane textPane = this.bruteForceManager.getResult();
203             textPane.getDocument().insertString(
204                 textPane.getDocument().getLength(),
205                 (textPane.getDocument().getLength() == 0 ? StringUtils.EMPTY : "\n") + text,
206                 null
207             );
208         } catch (BadLocationException e) {
209             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
210         }
211     }
212 }