Skip to content

Commit

Permalink
feat: merged feat for cryptography detection
Browse files Browse the repository at this point in the history
  • Loading branch information
Psingle20 committed Nov 27, 2024
2 parents e2702c9 + 7cf24ee commit f4a64e0
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/proxy/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const pushActionChain = [
proc.push.checkForAiMlUsage,
proc.push.checkExifJpeg,
proc.push.clearBareClone,
proc.push.checkCryptoImplementation,
proc.push.scanDiff,
proc.push.blockForAuth,
];
Expand Down
140 changes: 140 additions & 0 deletions src/proxy/processors/push-action/checkCryptoImplementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const Step = require('../../actions').Step;

// Common encryption-related patterns and keywords
const CRYPTO_PATTERNS = {
// Known non-standard encryption algorithms
nonStandardAlgorithms: [
'xor\\s*\\(',
'rot13',
'caesar\\s*cipher',
'custom\\s*encrypt',
'simple\\s*encrypt',
'homebrew\\s*crypto',
'custom\\s*hash'
],

// Suspicious operations that might indicate custom crypto Implementation
suspiciousOperations: [
'bit\\s*shift',
'bit\\s*rotate',
'\\^=',
'\\^',
'>>>',
'<<<',
'shuffle\\s*bytes'
],

// Common encryption-related variable names
suspiciousVariables: [
'cipher',
'encrypt',
'decrypt',
'scramble',
'salt(?!\\w)',
'iv(?!\\w)',
'nonce'
]
};

function analyzeCodeForCrypto(diffContent) {
const issues = [];
// Check for above mentioned cryto Patterns
if(!diffContent) return issues;

CRYPTO_PATTERNS.nonStandardAlgorithms.forEach(pattern => {
const regex = new RegExp(pattern, 'gi');
const matches = diffContent.match(regex);
if (matches) {
issues.push({
type: 'non_standard_algorithm',
pattern: pattern,
matches: matches,
severity: 'high',
message: `Detected possible non-standard encryption algorithm: ${matches.join(', ')}`
});
}
});

CRYPTO_PATTERNS.suspiciousOperations.forEach(pattern => {
const regex = new RegExp(pattern, 'gi');
const matches = diffContent.match(regex);
if (matches) {
issues.push({
type: 'suspicious_operation',
pattern: pattern,
matches: matches,
severity: 'medium',
message: `Detected suspicious cryptographic operation: ${matches.join(', ')}`
});
}
});

CRYPTO_PATTERNS.suspiciousVariables.forEach(pattern => {
const regex = new RegExp(pattern, 'gi');
const matches = diffContent.match(regex);
if (matches) {
issues.push({
type: 'suspicious_variable',
pattern: pattern,
matches: matches,
severity: 'low',
message: `Detected potential encryption-related variable: ${matches.join(', ')}`
});
}
});

return issues;
}

const exec = async (req, action) => {
const step = new Step('checkCryptoImplementation');

try {
let hasIssues = false;
const allIssues = [];

for (const commit of action.commitData) {
const diff = commit.diff || '';
const issues = analyzeCodeForCrypto(diff);

if (issues.length > 0) {
hasIssues = true;
allIssues.push({
commit: commit.hash,
issues: issues
});
}
}

if (hasIssues) {
step.error = true;

const errorMessage = allIssues.map(commitIssues => {
return `Commit ${commitIssues.commit}:\n` +
commitIssues.issues.map(issue =>
`- ${issue.severity.toUpperCase()}: ${issue.message}`
).join('\n');
}).join('\n\n');

step.setError(
'\n\nYour push has been blocked.\n' +
'Potential non-standard cryptographic implementations detected:\n\n' +
`${errorMessage}\n\n` +
'Please use standard cryptographic libraries instead of custom implementations.\n' +
'Recommended: Use established libraries like crypto, node-forge, or Web Crypto API.\n'
);
}

action.addStep(step);
return action;
} catch (error) {
step.error = true;
step.setError(`Error analyzing crypto implementation: ${error.message}`);
action.addStep(step);
return action;
}
};

// exec.displayName = 'checkCryptoImplementation.exec';
exports.exec = exec;
exports.analyzeCodeForCrypto = analyzeCodeForCrypto;
1 change: 1 addition & 0 deletions src/proxy/processors/push-action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ console.log(__dirname);
exports.checkAuthorEmails = require('./checkAuthorEmails').exec;
exports.checkUserPushPermission = require('./checkUserPushPermission').exec;
exports.clearBareClone = require('./clearBareClone').exec;
exports.checkCryptoImplementation = require('./checkCryptoImplementation').exec;
exports.checkSensitiveData = require('./checkSensitiveData').exec;
exports.checkForAiMlusage = require('./checkForAiMlUsage').exec;
exports.checkExifJpeg = require('./checkExifJpeg').exec;
9 changes: 9 additions & 0 deletions test/chain.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const mockPushProcessors = {
audit: sinon.stub(),
checkRepoInAuthorisedList: sinon.stub(),
checkCommitMessages: sinon.stub(),
checkCryptoImplementation: sinon.stub(),
checkAuthorEmails: sinon.stub(),
checkUserPushPermission: sinon.stub(),
checkIfWaitingAuth: sinon.stub(),
Expand All @@ -36,6 +37,7 @@ mockPushProcessors.parsePush.displayName = 'parsePush';
mockPushProcessors.audit.displayName = 'audit';
mockPushProcessors.checkRepoInAuthorisedList.displayName = 'checkRepoInAuthorisedList';
mockPushProcessors.checkCommitMessages.displayName = 'checkCommitMessages';
mockPushProcessors.checkCryptoImplementation.displayName = 'checkCryptoImplementation';
mockPushProcessors.checkAuthorEmails.displayName = 'checkAuthorEmails';
mockPushProcessors.checkUserPushPermission.displayName = 'checkUserPushPermission';
mockPushProcessors.checkIfWaitingAuth.displayName = 'checkIfWaitingAuth';
Expand Down Expand Up @@ -110,6 +112,7 @@ describe('proxy chain', function () {
mockPushProcessors.checkEXIFJpeg.resolves(continuingAction);
mockPushProcessors.checkAuthorEmails.resolves(continuingAction);
mockPushProcessors.checkUserPushPermission.resolves(continuingAction);
mockPushProcessors.checkCryptoImplementation.resolves(continuingAction);
mockPushProcessors.checkSensitiveData.resolves(continuingAction);

// this stops the chain from further execution
Expand All @@ -125,6 +128,7 @@ describe('proxy chain', function () {
expect(mockPushProcessors.checkIfWaitingAuth.called).to.be.true;
expect(mockPushProcessors.pullRemote.called).to.be.false;
expect(mockPushProcessors.audit.called).to.be.true;
expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true;

expect(result.type).to.equal('push');
expect(result.allowPush).to.be.false;
Expand All @@ -136,10 +140,12 @@ describe('proxy chain', function () {
const continuingAction = { type: 'push', continue: () => true, allowPush: false };
mockPreProcessors.parseAction.resolves({ type: 'push' });
mockPushProcessors.parsePush.resolves(continuingAction);
mockPushProcessors.checkCryptoImplementation.resolves(continuingAction);
mockPushProcessors.checkRepoInAuthorisedList.resolves(continuingAction);
mockPushProcessors.checkCommitMessages.resolves(continuingAction);
mockPushProcessors.checkAuthorEmails.resolves(continuingAction);
mockPushProcessors.checkUserPushPermission.resolves(continuingAction);

// this stops the chain from further execution

mockPushProcessors.checkIfWaitingAuth.resolves({ type: 'push', continue: () => true, allowPush: true });
Expand All @@ -154,6 +160,7 @@ describe('proxy chain', function () {
expect(mockPushProcessors.checkIfWaitingAuth.called).to.be.true;
expect(mockPushProcessors.pullRemote.called).to.be.false;
expect(mockPushProcessors.audit.called).to.be.true;
expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true;

expect(result.type).to.equal('push');
expect(result.allowPush).to.be.true;
Expand All @@ -177,6 +184,7 @@ describe('proxy chain', function () {
mockPushProcessors.clearBareClone.resolves(continuingAction);
mockPushProcessors.scanDiff.resolves(continuingAction);
mockPushProcessors.blockForAuth.resolves(continuingAction);
mockPushProcessors.checkCryptoImplementation.resolves(continuingAction);

const result = await chain.executeChain(req);

Expand All @@ -195,6 +203,7 @@ describe('proxy chain', function () {
expect(mockPushProcessors.scanDiff.called).to.be.true;
expect(mockPushProcessors.blockForAuth.called).to.be.true;
expect(mockPushProcessors.audit.called).to.be.true;
expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true;
expect(mockPushProcessors.checkSensitiveData.called).to.be.true;

expect(result.type).to.equal('push');
Expand Down
Loading

0 comments on commit f4a64e0

Please sign in to comment.